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()只是唤醒所有等待这个特定锁的任务而已。
上一篇: 21章 并发