为什么b.wait()不让主线程等待

时间:2018-06-21 15:47:54

标签: java multithreading

不确定b.wait()为什么不等待主线程。如果我们创建一个虚拟对象,则Object a = new Object();它等待。如果我使用Thread扩展ThreadA并为ThreadA创建实例并使用ThreadA引用进行锁定,则它可以工作。但是为什么下面的wait()不起作用

package com.aircell;

public class ThreadA{
    public static void main(String[] args){
        ThreadB b = new ThreadB();
        b.start();
        System.out.println("who is this thread");
        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;

            }

        }
        System.out.println("done thread");
    }
}

3 个答案:

答案 0 :(得分:0)

首先:如果我在这里尝试您的课程,我会得到以下输出:

who is this thread
Waiting for b to complete...
done thread
Total is: 4950

它确实起作用了,这有点令人惊讶,但我认为wait的Javadoc中的以下句子似乎发生在这里:

  

就像在一个参数版本中一样,可能会发生中断和虚假唤醒,因此应始终在循环中使用此方法。

以下更改应为您提供要实现的行为:

public class ThreadA{
    public static void main(String[] args){
        ThreadB b = new ThreadB();
        System.out.println("who is this thread");
        synchronized(b){
            b.start();
            try{
                System.out.println("Waiting for b to complete...");
                while (!b.finished) {
                    b.wait();
                }
            }catch(InterruptedException e){
                e.printStackTrace();
            }

            System.out.println("Total is: " + b.total);
        }
    }
}

class ThreadB extends Thread{
    int total;
    boolean finished;
    @Override
    public void run(){
        synchronized(this){
            try {
                for(int i=0; i<100 ; i++){
                    total += i;
                }
            }
            finally {
                finished = true;
                this.notifyAll();
            }
        }
        System.out.println("done thread");
    }
}

答案 1 :(得分:0)

精彩的问题。花了我几个小时来解决这个问题。

当线程完成执行时,JVM将通知线程对象(在本例中为对象“ b”)。

因此,在主线程中,如果在ThreadB完成之前执行已达到b.wait(),则将调用隐式b.notify()来通知主线程。您的代码中发生的序列是以下2之一:

案例1:

  • b.start()被呼叫。
  • 但是,在执行线程B之前,主线程会进入同步块,获取锁并调用b.wait()
  • b.wait()释放锁,调度主线程,然后threadB开始执行。
  • threadB完成执行并释放锁。
  • 由于threadB完成,因此在Thread对象上调用notify()。即JVM会触发一个隐式b.notify()
  • 主线程被唤醒并完成它的任务。

第二种情况:

  • b.start()被呼叫。
  • threadB开始执行,然后主线程才能获取锁。主线程在synchronized(b)上被阻止
  • threadB完成执行并释放锁。
  • 主线程获取锁并进入synchronization块并调用b.wait()。
  • 由于threadB完成,因此在Thread对象上调用notify()。即JVM会触发一个隐式b.notify()
  • b.wait()释放锁,调度主线程,然后第二个线程开始执行。
  • 主线程被唤醒并完成它的任务。

但是,如果您在主线程中添加了延迟。在主线程可以执行b.wait()之前,足以使ThreadB完成,您将看到主线程在等待。如果您输入Thread.sleep(2000);

答案 2 :(得分:-2)

wait()方法不能保证执行首先等待完成,但是如果您希望一个线程结束