Ausgabe
Ich lerne für OCJP und bin jetzt im Kapitel “Thread”. Ich habe einige Fragen zu Warte- und Benachrichtigungsmethoden. Ich glaube, ich verstehe, was hier passiert, aber ich möchte nur sichergehen, dass ich auf dem richtigen Weg bin. Ich habe diesen Code als Beispiel geschrieben:
package threads;
public class Main {
static Object lock = new Object();
public static void main(String[] args) {
new Main().new FirstThread().start();
new Main().new SecondThread().start();
}
class FirstThread extends Thread {
public void run() {
synchronized (lock) {
lock.notify();
System.out.println("I've entered in FirstThread");
}
}
}
class SecondThread extends Thread {
public void run() {
synchronized (lock) {
try {
lock.wait();
System.out.println("I'm in the second thread");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
In diesem Beispiel ist die Konsolenausgabe I've entered in FirstThread
, da der erste Thread startet, die Methode translate() aufgerufen wird, dann der zweite Thread startet, die Methode wait() aufgerufen wird und der String “I’m in the second thread” nicht ausgegeben wird .
Das nächste Szenario ist, dass ich die Positionen von umkehre new Main().new FirstThread().start();
und new Main().new SecondThread().start();
die Ausgabe ist
I've entered in FirstThread
I'm in the second thread
Da der zweite Thread startet, wird die Methode wait() aufgerufen, dann startet der erste Thread, die Methode notification() wird aufgerufen, die Konsole I've entered in FirstThread
gibt aus, das Warten wird freigegeben und I'm in the second thread
in der Konsole ausgegeben.
Geschieht das, weil der Computer so schnell ist und die Threads sequentiell ablaufen? Theoretisch kann die zweite start()-Methode meiner Meinung nach zuerst aufgerufen werden, oder?.
Und die letzte Frage, die ich habe, ist, warum das Sperrobjekt statisch sein muss, denn wenn ich den statischen Modifikator entferne, ist die Ausgabe immer I've entered in FirstThread
?
Ich weiß, dass statische Felder in JVM geladen werden, wenn die Klasse geladen wird, aber ich kann die Logik von lock Object nicht verstehen.
Lösung
Die Threads werden nacheinander gestartet, und theoretisch würde Thread 1 vor Thread 2 ausgeführt werden, obwohl dies nicht garantiert ist (ziemlich sicher, dass es in diesem einfachen Fall konsistent sein wird, da es keine echten oder simulierten aleatorischen Verzögerungen gibt).
Aus diesem Grund hat Thread 2, wenn er etwas früher gestartet wird, die Möglichkeit, auf eine Sperre zu warten, die anschließend (von Thread 1) benachrichtigt wird, anstatt ewig auf eine Sperre zu warten, die bereits einmal benachrichtigt wurde (daher kein Drucken).
Auf der static
Sperre Object
: Sie binden Ihre [First/Second]Thread
verschachtelten Klassen an Instanzen von Main
, daher muss die Sperre beiden gemeinsam sein, wenn Sie möchten, dass sie mit derselben Sperre synchronisiert werden.
Wenn es sich um ein Instanzobjekt handeln würde, würden Ihre Threads auf eine andere Sperre zugreifen und sie synchronisieren, da Ihr new Main()...
Idiom zwei Instanzen von Main
und anschließend zwei Instanzen von erhalten würde lock
.
Beantwortet von – Mena
Antwort geprüft von – Jay B. (FixError Admin)