public class ThreadA {
public static void main(String[] args){
ThreadB b = new ThreadB();
b.start();
synchronized(b){
try{
System.out.println("Waiting for b to complete...");
b.wait();
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println("Total is: " + b.total);
}
}
}
class ThreadB extends Thread{
int total;
@Override
public void run(){
synchronized(this){
for(int i=0; i<100 ; i++){
total += i;
}
notify();
}
}
}
如上例所示,如果wait()
阻止首先进入,则ThreadB中的后续notify()
将告诉主线程继续。
但是我们不能保证wait()
将在notify(
之前执行),如果ThreadB首先进入该块怎么办? Notify()
将在wait()
之前执行,因此wait()
会永远挂在那里(因为没有notify()
告诉它继续)?什么通常是处理这个问题的正确方法?
答案 0 :(得分:9)
你应该几乎总是有一个谓词和wait / notify。也就是说,你需要一个条件 您可以检查,例如变量变为true,队列变为空/满等等。只是盲目地等待某人调用.notify()只有很少的用例。
所以,以下是不行的,因为你说的原因,另一个线程可以在ThreadA调用之前调用.notify()。。()
public class ThreadA {
public static Object latch = new Object();
public static void main(String[] args) {
ThreadB b = new ThreadB();
b.start();
synchronized(latch ) {
latch.wait(); //wait for B to finish a calculation
}
System.out.println("Total is: " + b.total);
}
}
class ThreadB extends Thread {
int total;
@Override
public void run() {
for (int i = 0; i < 100; i++) {
total += i;
}
synchronized(ThreadA.latch) {
ThreadA.latch.notify();
}
}
}
你需要做这样的事情:
public class ThreadA {
public static Object latch = new Object();
public static boolean done = false;
public static void main(String[] args) {
ThreadB b = new ThreadB();
b.start();
synchronized(latch ) {
while (!done) { //wait for B to indicate it is finished.
latch.wait();
}
}
System.out.println("Total is: " + b.total);
}
}
class ThreadB extends Thread {
int total;
@Override
public void run() {
for (int i = 0; i < 100; i++) {
total += i;
}
synchronized(ThreadA.latch) {
ThreadA.done = true;
ThreadA.latch.notify();
}
}
}
请注意,在上面,done
变量受同步块保护,.wait()
将自动释放/重新获取该锁定。所以没有竞争条件,如果在我们进入.wait()
调用之前调用.notify(),ThreadA会发现因为done
将是true
而不进入{{ 1}}打电话。
对于像这段代码这样的简单案例,您可以等待ThreadB结束,可以使用.wait()
答案 1 :(得分:1)
我想你想做这样的事情
public class ThreadA {
public static void main(String[] args) {
ThreadB b = new ThreadB();
b.start();
b.join(); // Wait for thread b to finish
System.out.println("Total is: " + b.total);
}
}
您还应该让ThreadB只实现Runnable
而不是扩展Thread
。
class ThreadB implements Runnable {
int total;
public void run() {
for (int i = 0; i < 100; i++) {
total += i;
}
}
}
然后使用它
ThreadB tb = new ThreadB();
Thread b = new Thread(tb);
答案 2 :(得分:1)
您的问题的许多可能解决方案之一是:
public class ThreadA {
public static final CyclicBarrier barrier = new CyclicBarrier(2);
public static void main(String[] args) {
ThreadB b = new ThreadB();
b.start();
try {
barrier.await();
System.out.println("Total is: " + b.total);
} catch (InterruptedException | BrokenBarrierException ex) {
}
}
}
class ThreadB extends Thread {
int total;
@Override
public void run() {
for (int i = 0; i < 100; i++) {
total += i;
}
try {
ThreadA.barrier.await();
} catch (InterruptedException | BrokenBarrierException ex) {
}
}
}