public class Test {
public static Object object = new Object();
public static boolean printA = true;
public static void main(String[] args) {
ThreadA threadA = new ThreadA();
threadA.start();
ThreadB threadB = new ThreadB();
threadB.start();
}
}
class ThreadA extends Thread {
@Override
public void run() {
for(int i = 0; i < 10; i++) {
synchronized (Test.object) {
if(!Test.printA) {
try {
Test.object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
System.out.println("A");
Test.printA = false;
Test.object.notify();
}
}
}
}
}
class ThreadB extends Thread {
@Override
public void run() {
for(int i = 0; i < 10; i++) {
synchronized (Test.object) {
if(Test.printA) {
try {
Test.object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
System.out.println("B");
Test.printA = true;
Test.object.notify();
}
}
}
}
}
运行以上代码,为什么会一直不结束无限wait下去?
------------------ 分割线,以下是正确的写法 -------------------
实际上线程中不应该有else,把else注释掉就正确了。 如果加上else后,该线程会在wait后不再notify,导致另一个线程无限wait。
public class Test {
public static Object object = new Object();
public static boolean printA = true;
public static void main(String[] args) {
ThreadA threadA = new ThreadA();
threadA.start();
ThreadB threadB = new ThreadB();
threadB.start();
}
}
class ThreadA extends Thread {
@Override
public void run() {
for(int i = 0; i < 10; i++) {
synchronized (Test.object) {
if(!Test.printA) {
try {
Test.object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}/* else {*/
System.out.println("A");
Test.printA = false;
Test.object.notify();
/*}*/
}
}
}
}
class ThreadB extends Thread {
@Override
public void run() {
for(int i = 0; i < 10; i++) {
synchronized (Test.object) {
if(Test.printA) {
try {
Test.object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}/* else { */
System.out.println("B");
Test.printA = true;
Test.object.notify();
/*}*/
}
}
}
}
リーリー
コードにコメントを追加し、i を 4 に減らして、分析しやすくします。一度実行して出力ログを確認すると、どこに問題があるかがわかります。
実際、問題は A が実行を終了し、B が待機状態にあるため、誰も通知しに来ないことです。A をもう一度ループするだけで済みます。
これは生産者と消費者の問題に非常に似ています。あなたの質問の中で
wait
が無限に続く唯一の状況は、ThreadA
またはThreadB
のいずれかが実行を終了し、スレッドwait
が実行を終了していない場合、そのスレッドが実行されているため、もう一方のスレッドはそれをウェイクアップできません。もう終わった。スレッド A が最初に実行されます。B がまだ待機していない場合、この時点で通知は無効になり、A の通知は実行を終了します。このように書くロジックに何か問題があります
明らかに ThreadB が最初に待機しますが、コードは最初に ThreadA を呼び出します。ThreadB を最初に実行するだけです
リーリー