欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Thinking in java 第21章 并发 notify()与nofityAll()

程序员文章站 2022-05-07 08:37:45
...

     因为在技术上而言,可能会有多个任务在单个car对象上处于wait()状态,因此调用notifyAll()比只调用nofity()更加安全。但是,上面的程序的结构只会有一个任务实际处于wait()状态,因此你可以使用nofity*()来代替nofityAll().

     使用notify()而不是notifyAll()是一种优化,使用notify()时,在众多等待同一个锁的任务中只有一个会被唤醒,因此如果你希望使用notify(),就必须保证被唤醒的时恰当的任务。另外,为了使用notify(),所有任务必须等待相同的条件,因为如果你有多个任务在等待不同的条件,那么你就不能知道是否唤醒了恰当的任务。如果使用notify(),当条件发生变化时,必须只有一个任务能从中受益。最后,这些限制对所有可能存在的子类都必须总时起作用的,如果这些规则中有任何一条不满足,那么你就必须使用notify()而不是notify().

     在有关java的线程机制的讨论中,有一个令人困惑的描述:notifyAll()将唤醒"所有正在等待的任务"。这是否意味着在程序中任何地方,任何处于wait()状态中的任务都将被任何对notiyAll()的调用呢?在下面的示例中,与Task2相关的代码说明了情况并非如此--事实上,当notifyAll()因某个特定锁而被调用时,只有等待这个锁的任务才会被唤醒。

class Bloker {
    synchronized void waitingCall(){
        try {
            while(!Thread.interrupted()){
                wait();
                System.out.println(Thread.currentThread() + " ");
            }
        } catch (InterruptedException e) {
            System.out.println("exit");
        }
    }
    synchronized void prod(){notify();}
    synchronized void prodAll(){notifyAll();}
}
class Task implements Runnable {
    static Bloker bloker = new Bloker();

    @Override
    public void run() {
        bloker.waitingCall();
    }
}

class Task2 implements Runnable {
    static Bloker bloker = new Bloker();
    @Override
    public void run() {
        bloker.waitingCall();
    }
}

public class NotifyVsNotifyAll {
    public static void main(String[] args) throws Exception{
        ExecutorService exec = Executors.newCachedThreadPool();
        IntStream.range(0,5).forEach(i->{
            exec.execute(new Task());
        });
        exec.execute(new Task2());
        Timer timer = new Timer();
        timer.scheduleAtFixedRate(new TimerTask() {
            boolean prod = true;
            @Override
            public void run() {
                if(prod){
                    System.out.println("\nnotify()");
                    Task.bloker.prod();
                    prod = false;
                }else{
                    System.out.println("\nnotifyAll()");
                    Task.bloker.prodAll();
                    prod = true;
                }
            }
        },400,400);
        TimeUnit.SECONDS.sleep(5);
        timer.cancel();
        System.out.println("\nTimer canceled");
        System.out.println("Task2 blocker prodAll()");
        Task2.bloker.prodAll();
        TimeUnit.MILLISECONDS.sleep(500);
        System.out.println("\nShutting down");
        exec.shutdownNow();
    }

}

notify()
Thread[pool-1-thread-1,5,main] 

notifyAll()
Thread[pool-1-thread-1,5,main] 
Thread[pool-1-thread-2,5,main] 
Thread[pool-1-thread-3,5,main] 
Thread[pool-1-thread-4,5,main] 
Thread[pool-1-thread-5,5,main] 

Timer canceled
Task2 blocker prodAll()
Thread[pool-1-thread-6,5,main] 

Shutting down

运行上面的程序,可以看出,Task2的线程从来都没有被唤醒过,虽然使用了notifyAll(),所以,notifyAll()只是唤醒所有等待这个特定锁的任务而已。