webentwicklung-frage-antwort-db.com.de

Einfädeln in Java: Wie sperren Sie ein Objekt?

Die folgende Funktion wird in einem eigenen Thread ausgeführt:

private void doSendData()
{
    try {

           //writeToFile(); // just a temporary location of a call
           InetAddress serverAddr = InetAddress.getByName(serverAddress);
           serverAddr.wait(60000);
           //Log.d("TCP", "C: Connecting...");
           Socket socket = new Socket(serverAddr, portNumber);
           socket.setSoTimeout(3000);

               try {
                //Log.d("TCP", "C: Sending: '" + message + "'");
                PrintWriter out = new PrintWriter( new BufferedWriter( new OutputStreamWriter(socket.getOutputStream())),true);
                String message = packData();
                out.println(message);
                Log.d("TCP", "C: Sent.");
                Log.d("TCP", "C: Done.");
                connectionAvailable = true;

             } catch(Exception e) {
                 Log.e("TCP", "S: Error", e);
                 connectionAvailable = false;

               } finally {
                  socket.close();
                  announceNetworkAvailability(connectionAvailable);
                }

         } catch (Exception e) {
              Log.e("TCP", "C: Error", e);
              announceNetworkAvailability(connectionAvailable);
         }
}

Wenn die Ausführung die Zeile serverAddr.wait(60000) erreicht, wird eine Exception ausgelöst:

Java.lang.IllegalMonitorStateException: object not locked by thread before wait()

Weiß jemand, wie man ein Objekt oder eine Funktion sperrt, um die Parallelität zu verhindern? Ich habe versucht, ein Sperrobjekt hinzuzufügen:

private final Lock lock = new ReentrantLock();

und die Linie

boolean locked = lock.tryLock();

am Anfang der Funktion, aber es hat nicht funktioniert.

33
Niko Gamulin

Um wait () für ein Objekt aufzurufen, müssen Sie die synchronisierte Sperre für dieses Objekt aufrechterhalten (obwohl die Sperre tatsächlich aufgehoben wird, während der Thread wartet):

synchronized (serverAddr) {
  serverAddr.wait();
}

Ich muss zugeben, dass - warum Sie dies in diesem Fall verblüffen wollen ...

64
Neil Coffey

Vielleicht suchen Sie nach der Methode Thread.sleep (long) ? Diese Methode wird wait (wie in stop die Ausführung des Threads) für die angegebene Zeit in Millisekunden dauern, bevor sie fortgesetzt wird. 

object.wait (long) (was Sie verwenden) macht etwas ganz anderes. Er wartet darauf, dass ein anderes Objekt von einem anderen Thread benachrichtigt wird (z. B. eine Art Wecknachricht senden) und wartet höchstens die angegebene Anzahl von Millisekunden. Angesichts des Codes, den Sie gepostet haben, bezweifle ich sehr, dass Sie das wirklich wollen.

Wenn Thread.sleep () nicht das ist, was Sie möchten, sollten Sie den synchronisierten Block wie in den anderen Postern erwähnt verwenden.

21
LordOfThePigs

Ich habe immer Angst, wenn ich so einen Code sehe. Tun Sie sich selbst einen Gefallen und schauen Sie sich das Java.util.concurrent-Paket an.

11
Apocalisp

Die oben genannten sind richtig. Sie können einen synchronisierten Codeblock verwenden. Oder Sie können ein so genanntes Mutex erstellen. Ein Mutex kann tatsächlich ein beliebiges Objekt sein. Viele Leute verwenden Object selbst nur als Mutex. Dann können Sie den Mutex sperren. Alle Threads, die Zugriff erhalten möchten, müssen darauf warten, dass Thread den Mutex hält, um ihn freizugeben.

Es gab auch einen Vorschlag von Apocalisp. Ich würde auch empfehlen, dass Sie sich das Java.util.concurrent-Paket ansehen.

1
uriDium

Um diese Fehlermeldung zu vermeiden, verwenden Sie das synchronisierte Schlüsselwort:

synchronized(serverAddr){
  serverAddr.wait(60000);
}
1
krosenvold

Der folgende Code sollte funktionieren.

     private final ReentrantLock lock = new ReentrantLock();

     lock.lock();  // block until condition holds
     try {
        serverAddr.wait(60000);
     } finally {
       lock.unlock()
     }
   }

Weitere Informationen finden Sie in dieser Dokumentation Seite

public void lock()

Erwirbt die Sperre.

Übernimmt die Sperre, wenn sie nicht von einem anderen Thread gehalten wird, und kehrt sofort zurück, wobei der Sperrzählwert auf Eins gesetzt wird.

Wenn der aktuelle Thread die Sperre bereits hält, wird der Hold-Zähler um eins erhöht und die Methode kehrt sofort zurück.

Wenn die Sperre von einem anderen Thread gehalten wird, wird der aktuelle Thread für Thread-Planungszwecke deaktiviert und bleibt so lange inaktiv, bis die Sperre abgerufen wurde. Zu diesem Zeitpunkt wird die Anzahl der Sperren auf 1 gesetzt

Siehe diese SE-Frage, um die Vorteile von lock gegenüber synchronization zu kennen: 

Synchronisation vs. Sperre

0
Ravindra babu

Wenn Sie in Java über ein Multithread-Programm verfügen, müssen Sie im Allgemeinen die gemeinsam genutzte Variable mithilfe von synchronisiertem (Schlüsselwort) sperren. Anschließend kann nur ein Thread auf den gemeinsam genutzten Speicher zugreifen.

0
Khash Nejad