因为在技术上,可能会由多个任务在单个Car对象上处于wait状态,因此调用notifyAll比只调用notify要更安全。但是,上面程序的结构只会有一个任务实际处于wait状态,因此你可以使用notify来代替notifyAll。
使用notify而不是notifyAll是一种优化。使用notify时,在众多等待同一个锁的任务中只有一个会被唤醒,因此如果你希望使用notify,就必须保证被唤醒的恰当的任务,另外,为了使用notify,所有任务必须等待相同的条件,因为如果你有多个任务在等待不同的条件,那么你就不会知道是否唤醒了恰当的任务。如果使用notfy,当条件发生变化时,必须只有一个任务能够从中受益。最后,这些限制对所有可能存在的子类都必须总是起作用的。如果这些规则中有任何一条不满足,那么比就必须使用notifyAll而不是notify.
在有关Java的线程机制的讨论中,有一个令人困惑的描述:notifyAll将唤醒“所有正在等待的任务”。这是否意味着在程序中任何地方,任何处于wait状态中的任务都将被任何对notifyAll的调用唤醒呢?在下面的示例中,与Task2相关的代码说明了情况并非如此–事实上,当notifyAll因某个特定锁而被调用时,只有等待这个锁的任务才会被唤醒:

import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;class Blocker {synchronized void waitingCall() {try {while (!Thread.interrupted()) { //检查当前线程的中断标志,返回一个Boolean并清除中断状态wait();//阻塞System.out.println(Thread.currentThread() + " ");}} catch (InterruptedException e) {//Ok to exit this way}}synchronized void prod() {notify();//解除阻塞}synchronized void prodAll() {notifyAll();}
}class Task implements Runnable {static Blocker block = new Blocker();@Overridepublic void run() {block.waitingCall();}
}class Task2 implements Runnable {//一个单独的Blocker对象static Blocker block = new Blocker();@Overridepublic void run() {block.waitingCall();}
}public class NotifyVsNotifyAll {public static void main(String[] args) throws InterruptedException {ExecutorService executorService = Executors.newCachedThreadPool();for (int i = 0; i < 5; i++) {executorService.execute(new Task());}executorService.execute(new Task2());Timer timer = new Timer(); // 定时器timer.scheduleAtFixedRate(new TimerTask() { //周期性执行 定时任务boolean prod = true;@Overridepublic void run() {if (prod) {System.out.println("\nnotify()");Task.block.prod();prod = false;} else {System.out.println("\nnotifyAll()");Task.block.prodAll();prod = true;}}},400,400);TimeUnit.SECONDS.sleep(5);timer.cancel();//计时器被撤销了System.out.println("\nTimer canceled");TimeUnit.MILLISECONDS.sleep(500);Task2.block.prodAll();TimeUnit.MILLISECONDS.sleep(500);System.out.println("\nShutting down");executorService.shutdownNow();}
}

Task和Task2每个都有其自己的Blocker对象,因此每个Task对象都会在Task,blocker上阻塞,而每个Task2都会在Task2.blocker上阻塞。在main中,java.util.Timer对象被设置为每0.4秒执行异常run方法,而这个run方法将经由"激励"方法交替地在Task.blocker上调用notify和notifyAll。
从输出中你可以看到,即使存在Task2.blocker上阻塞的Task2对象,也没有任何在Tasl.blocker上的notify或notifyAll调用会导致Task2对象被唤醒。与此类似,在main的结尾,调用了timer的cancel,即使计时器被撤销了,前五个任务也依然在运行,并仍旧在它们对Task.blocker.waitingCall的调用中被阻塞。对Task2.blocker.prodAll的调用所产生的输出不包括任何在Task.blocker中的锁上等待的任务。
如果你浏览Blocker中的prod和prodAll,就会发现这是有意义的。这些方法是synchronized的,这意味着它们将获取自身的锁,因此当它们调用notify或notifyAll时,只在这个锁上调用是符合逻辑的—因此,将只唤醒在等待这个特定锁的任务。
Blocker.waitingCall非常简单,以至于在本例中,你需声明for而不是while就可以达到相同的效果,因为本例中,由于异常而离开循环和通过检查interrupted标志离开循环是没有任何区别–在两种情况下都要执行相同的代码。但是,事实上,这个示例选择了检查Interrupted,因为存在着两种离开循环的方式。如果在以后得某个时刻,你决定要循环中添加更多的代码,那么如果没有覆盖从这个循环中退出的这两条路径就会产生引入错误的风险。

notify()与notifyAll相关推荐

  1. 用实例揭示notify()和notifyAll()的本质区别

    用实例揭示notify()和notifyAll()的本质区别 收藏 notify()和notifyAll()都是Object对象用于通知处在等待该对象的线程的方法.两者的最大区别在于: notifyA ...

  2. Java多线程协作(wait、notify、 notifyAll)

    http://sunjun041640.blog.163.com/blog/static/25626832201041411210560/ Java监视器支持两种线程:互斥和 协作. 前面我们介绍了采 ...

  3. 【Java 线程的深入研究3】最简单实例说明wait、notify、notifyAll的使用方法

    wait().notify().notifyAll()是三个定义在Object类里的方法,可以用来控制线程的状态. 这三个方法最终调用的都是jvm级的native方法.随着jvm运行平台的不同可能有些 ...

  4. 最简实例说明wait、notify、notifyAll的使用方法

    /** *  转载请注明作者longdick    http://longdick.iteye.com * */ wait().notify().notifyAll()是三个定义在Object类里的方 ...

  5. 多线程:线程之间的协作(join、wait、notify、notifyAll、await、signal、signalAll)

    当多个线程可以一起工作去解决某个问题时,如果某些部分必须在其它部分之前完成,那么就需要对线程进行协调. join() 在线程中调用另一个线程的 join() 方法,会将当前线程挂起,而不是忙等待,直到 ...

  6. 为什么wait、notify、notifyAll方法定义在Object中而不是Thread类中

    多线程概述 Java是一个支持多线程的开发语言,多线程并发执行任务可以充分利用CPU资源,提高多任务并发执行效率(注意区分:多线程并不会加快任务的执行速度,而是可以充分利用多核CPU让线程轮流进行工作 ...

  7. 19、Java并发编程:线程间协作的两种方式:wait、notify、notifyAll和Condition

    Java并发编程:线程间协作的两种方式:wait.notify.notifyAll和Condition 在前面我们将了很多关于同步的问题,然而在现实中,需要线程之间的协作.比如说最经典的生产者-消费者 ...

  8. Java并发编程—notify和notifyAll有什么区别?

    原文作者:知乎用户 原文地址:https://www.zhihu.com/question/37601861/answer/145545371 著作权归作者所有.商业转载请联系作者获得授权,非商业转载 ...

  9. Java并发编程—线程间协作方式wait()、notify()、notifyAll()和Condition

    原文作者:Matrix海 子 原文地址:Java并发编程:线程间协作的两种方式:wait.notify.notifyAll和Condition 目录 一.wait().notify()和notifyA ...

  10. 如何在 Java 中正确使用 wait, notify 和 notifyAll – 以生产者消费者模型为例

    欢迎支持笔者新作:<深入理解Kafka:核心设计与实践原理>和<RabbitMQ实战指南>,同时欢迎关注笔者的微信公众号:朱小厮的博客. wait, notify 和 noti ...

最新文章

  1. nginx+tomcat+memcache实现负载均衡、session共享
  2. 通用软件测试的6个角度
  3. chrome浏览器上传文件延迟_扫描识别工具Dynamic Web TWAIN使用教程:移动浏览器捕获(下)...
  4. 转载/JSTL/attribute value does not accept any express
  5. es like模糊匹配_es 基于match_phrase/fuzzy的模糊匹配原理及使用
  6. 2003下的共享问题
  7. 《R数据可视化手册》——2.5 绘制箱线图
  8. namenode倒换原因分析
  9. iOS脚本一键生成各种尺寸的icon
  10. 在matlab中画收敛域,已知用下列差分方程描述的一个线性移不变因果系统(用MATLAB方法求解)。y(n)=y(n-1)+y(n-2)十x(n-1.. - 上学吧找答案...
  11. R语言25-Prosper 贷款数据分析1
  12. php wget下载图片,如何通过php或wget从Slack下载图像
  13. Linux监控多台远程服务器磁盘空间剩余情况并发送预警邮件以及电话告警
  14. Eclipse安装( jdk安装以及环境配置教程 )
  15. Spring MVC基础四
  16. 永磁电机风力发电机原理及并网实验系统QY-TF18
  17. 后疫情时代,打造15分钟交通圈
  18. Hive中的四种排序
  19. TTE系统容错设计(1) ——集中守护机制
  20. Linux网络编程IPv4和IPv6的inet_addr、inet_aton、inet_pton等函数小结

热门文章

  1. gmp计算机系统验证意义,GMP计算机系统验证
  2. k8s部署kube-prometheus
  3. Sun Solaris 修改IP地址或者主机名
  4. jq指定的所有class添加样式
  5. kafka基础入门_CodingPark编程公园
  6. 批量修改数据库,比如给数据库的某个表添加一个字段
  7. 面试害怕被问MySQL相关问题 ?这份三万字精华总结 + 面试100 问,吊打面试官完全够了
  8. [COCI2017-2018#3] Aron
  9. 风变科技公司的python小课_在风变科技学编程,拒绝做职场“边缘人”
  10. 如何通过C#读取PI实时数据