Java Notify()不使用Wait()

Java Notify()不使用Wait(),java,multithreading,wait,notify,Java,Multithreading,Wait,Notify,我不熟悉线程和学习,但在下面的代码中,为什么notify不起作用。根据我的理解,notify应该执行主线程,并在i=5时打印总数。如果我错了,请改正 public class ThreadA { public static void main(String[] args){ ThreadB b = new ThreadB(); b.start(); synchronized(b){ try{ System.out.println(

我不熟悉线程和学习,但在下面的代码中,为什么notify不起作用。根据我的理解,notify应该执行主线程,并在i=5时打印总数。如果我错了,请改正

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<10 ; i++){
                total += i;
             if(i==5){ 
                 System.out.println("Notify");
                 notify();
                 }
                System.out.println("Total is in cal thread: "+i+":" + total);
            }

        }
    }
}
当你说:

根据我的理解,notify应该执行主线程,并在i=5时打印总数

这不是怎么回事;无论将调用放在同步块中的什么位置,通知都不会发生,直到通知线程释放锁。ThreadB在主线程收到通知之前完成for循环的执行。接收通知的线程在此之前无法执行任何操作,它需要先获取锁,然后才能离开wait方法。这就是为什么在“总计为”行之前打印出所有“总计为校准”行的原因

如果希望“Total is”提前显示,则必须更改ThreadB以更快地释放其锁。您可以将同步移动到for循环中,以便在每次增量后释放锁

在这里,调用notify实际上是多余的,您可以注释掉它,程序仍然可以工作

这里发生的事情是,因为您使用线程b作为锁,当该线程终止时,等待获取它的任何线程都会收到该线程。以下章节对此进行了描述:

此实现使用This.wait调用的循环,该循环以This.isAlive为条件。当线程终止时,调用this.notifyAll方法。建议应用程序不要在线程实例上使用wait、notify或notifyAll

如果您运行我更改为使用不同锁(不是线程)的这个版本的程序,您可以看到没有此类隐式通知,并且程序调用notify是否真的很重要。在此版本中,注释掉线程b完成的通知将导致程序挂起

public class ThreadA {      
    public static final Object lock = new Object();     
    public static void main(String[] args){
        ThreadB b = new ThreadB();
        b.start();
        synchronized(lock){
            try{
                System.out.println("Waiting for b to complete...");
                lock.wait();
            }catch(InterruptedException e){
                e.printStackTrace();
            }
            System.out.println("Total is: " + b.total);
        }
        System.out.println("done");
    }
}

class ThreadB extends Thread{
    int total;
    @Override
    public void run(){
        synchronized(ThreadA.lock){
            for(int i=0; i<10 ; i++){
                total += i;
                if(i==5){ 
                    System.out.println("Notify");
                    ThreadA.lock.notify(); // hangs if you comment this out
                }
                System.out.println("Total is in cal thread: "+i+":" + total);
            }
        }
    }
}
公共类ThreadA{
公共静态最终对象锁=新对象();
公共静态void main(字符串[]args){
ThreadB=新的ThreadB();
b、 start();
已同步(锁定){
试一试{
System.out.println(“等待b完成…”);
lock.wait();
}捕捉(中断异常e){
e、 printStackTrace();
}
System.out.println(“总计为:+b.Total”);
}
系统输出打印项次(“完成”);
}
}
类ThreadB扩展线程{
整数合计;
@凌驾
公开募捐{
已同步(ThreadA.lock){
当你说:

根据我的理解,notify应该执行主线程,并在i=5时打印总数

这不是它的工作方式;在将调用放入notify的同步块中的何处并不重要,通知不会发生,直到通知线程释放锁。ThreadB在主线程收到通知之前完成for循环的执行。接收通知的线程在此之前无论如何都不能动作,它需要s在离开等待方法之前获取锁。这就是为什么所有“总计在校准”行在“总计在校准”行之前打印出来的原因

如果希望“Total is”提前显示,则必须更改ThreadB以更快地释放其锁。可以将同步移动到for循环中,以便在每次增量后释放锁

在这里,调用notify实际上是多余的,您可以注释掉它,程序仍然可以工作

这里发生的事情是,由于您使用线程b作为锁,因此当该线程终止时,等待获取它的任何线程都会接收到该锁

此实现使用以This.isAlive为条件的This.wait调用循环。当线程终止时,将调用This.notifyAll方法。建议应用程序不要在线程实例上使用wait、notify或notifyAll

如果您运行我更改为使用不同锁(不是线程)的这个版本的程序,您可以看到没有此类隐式通知,并且程序调用notify是否真正重要。在这个版本中,注释掉线程b完成的notify将导致程序挂起

public class ThreadA {      
    public static final Object lock = new Object();     
    public static void main(String[] args){
        ThreadB b = new ThreadB();
        b.start();
        synchronized(lock){
            try{
                System.out.println("Waiting for b to complete...");
                lock.wait();
            }catch(InterruptedException e){
                e.printStackTrace();
            }
            System.out.println("Total is: " + b.total);
        }
        System.out.println("done");
    }
}

class ThreadB extends Thread{
    int total;
    @Override
    public void run(){
        synchronized(ThreadA.lock){
            for(int i=0; i<10 ; i++){
                total += i;
                if(i==5){ 
                    System.out.println("Notify");
                    ThreadA.lock.notify(); // hangs if you comment this out
                }
                System.out.println("Total is in cal thread: "+i+":" + total);
            }
        }
    }
}
公共类ThreadA{
公共静态最终对象锁=新对象();
公共静态void main(字符串[]args){
ThreadB=新的ThreadB();
b、 start();
已同步(锁定){
试一试{
System.out.println(“等待b完成…”);
lock.wait();
}捕捉(中断异常e){
e、 printStackTrace();
}
System.out.println(“总计为:+b.Total”);
}
系统输出打印项次(“完成”);
}
}
类ThreadB扩展线程{
整数合计;
@凌驾
公开募捐{
已同步(ThreadA.lock){
对于(int i=0;i
调用
notify
只影响当前正在等待的线程,在调用后开始等待的线程将不会受到影响。在同步块内100%确认您等待的事情尚未发生之前,不要调用
wait


调用
notify
只会影响当前正在等待的线程,在调用后开始等待的线程不会受到影响。在同步块内100%确认您正在等待的事情尚未发生之前,不要调用
wait

如果是多线程,您不确定
b.w在调用
ThreadB
中的
notify()
之前,将调用
main
中的ait()
线程。当调用
b.start()
时,
ThreadB
run方法将在执行
main
线程的其余语句之前开始执行

如果在
n之后调用了
wait
synchronized(b) {
    try{
        // b.total needs to be volatile for this to work
        while (b.total < 5) {
            System.out.println("Waiting for b to complete...");
            b.wait();
        }
    }catch(InterruptedException e){
        e.printStackTrace();
    }
synchronized(b){
    try{
        System.out.println("Waiting for b to complete...");
        b.wait();
public class ThreadA {
    public static void main(String[] args) {
        ThreadB b = new ThreadB();
        b.start();

        try {
            b.join();
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }

        System.out.println("Waiting for b to complete...");
        System.out.println("Total is: " + b.total);
    }
}

class ThreadB extends Thread {
    int total;

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            total += i;
        }

    }
}