Java中为什么notify()可能导致死锁,而notifyAll()则不会(针对生产者-消费者模式)
1、先说两个概念:锁池 和 等待池
- 锁池:假设线程A已经拥有了某个对象(注意:不是类)的锁,而其它的线程想要调用这个对象的某个synchronized方法(或者synchronized块),由于这些线程在进入对象的synchronized方法之前必须先获得该对象的锁的拥有权,但是该对象的锁目前正被线程A拥有,所以这些线程就进入了该对象的锁池中。
- 等待池:假设一个线程A调用了某个对象的wait()方法,线程A就会释放该对象的锁后,进入到了该对象的等待池中
2、然后再来说 notify 和 notifyAll 的区别
- 如果线程调用了对象的 wait()方法,那么线程便会处于该对象的等待池中,等待池中的线程不会去竞争该对象的锁。
- 当有线程调用了对象的 notifyAll()方法(唤醒所有 wait 线程)或 notify()方法(只随机唤醒一个 wait 线程),被唤醒的的线程便会进入该对象的锁池中,锁池中的线程会去竞争该对象锁。也就是说,调用了notify后只要一个线程会由等待池进入锁池,而notifyAll会将该对象等待池内的所有线程移动到锁池中,等待锁竞争
- 优先级高的线程竞争到对象锁的概率大,假若某线程没有竞争到该对象锁,它还会留在锁池中,唯有线程再次调用 wait()方法,它才会重新回到等待池中。而竞争到对象锁的线程则继续往下执行,直到执行完了 synchronized 代码块,它会释放掉该对象锁,这时锁池中的线程会继续竞争该对象锁。
之前写过一个案例:Java多线程— —线程 虚假唤醒 问题剖析
解释一下原因:
Data类中的increment和decrement方法都是同步方法,所以多个调用过increment和decrement方法的线程都会进入等待池处于阻塞状态,等待一个正在运行的线程来唤醒它们。下面分别分析一下使用notify和notifyAll方法唤醒线程的不同之处:
使用了notify方法进行唤醒,而notify方法只能唤醒一个线程,其它等待的线程仍然处于wait状态,假设调用 increment 方法的线程执行完后,所有的线程都处于等待状态,此时 又执行了notify方法,这时如果唤醒的是一个increment方法的调度线程,那么while循环等于true,则此唤醒的线程也会处于等待状态,此时所有的线程都处于等待状态,那么也就没有了运行的线程来唤醒它们,这就发生了死锁。
如果使用notifyAll方法来唤醒所有正在等待该锁的线程,那么所有的线程都会处于运行前的准备状态(就是increment方法执行完后,唤醒了所有等待该锁的状态,注:不是wait状态),那么此时,即使再次唤醒一个increment方法调度线程,while循环等于true,唤醒的线程再次处于等待状态,那么还会有其它的线程可以获得锁,进入运行状态。
总结:notify方法很容易引起死锁,除非你根据自己的程序设计,确定不会发生死锁,notifyAll方法则是线程的安全唤醒方法。
Java中为什么notify()可能导致死锁,而notifyAll()则不会(针对生产者-消费者模式)的更多相关文章
- java中为什么notify()可能会导致死锁,而notifyAll()则不会
简单的说,notify()只唤醒一个正在等待的线程,当该线程执行完以后施放该对象的锁,而没有再次执行notify()方法,则其它正在等待的线程 则一直处于等待状态,不会被唤醒而进入该对象的锁的竞争池, ...
- Java并发编程()阻塞队列和生产者-消费者模式
阻塞队列提供了可阻塞的put和take方法,以及支持定时的offer和poll方法.如果队列已经满了,那么put方法将阻塞直到有空间可用:如果队列为空,那么take方法将会阻塞直到有元素可用.队列可以 ...
- java中的notify和notifyAll有什么区别?
先说两个概念:锁池和等待池 锁池:假设线程A已经拥有了某个对象(注意:不是类)的锁,而其它的线程想要调用这个对象的某个synchronized方法(或者synchronized块),由于这些线程在进入 ...
- java多线程15 :wait()和notify() 的生产者/消费者模式
什么是生产者/消费者模型 一种重要的模型,基于等待/通知机制.生产者/消费者模型描述的是有一块缓冲区作为仓库,生产者可将产品放入仓库,消费者可以从仓库中取出产品,生产者/消费者模型关注的是以下几个点: ...
- 关于java中生产者消费者模式的理解
在说生产者消费者模式之前,我觉得有必要理解一下 Obj.wait(),与Obj.notify()方法.wait()方法是指在持有对象锁的线程调用此方法时,会释放对象锁,同时休眠本线程.notify() ...
- 【重学Java】多线程基础(三种创建方式,线程安全,生产者消费者)
实现多线程 简单了解多线程[理解] 是指从软件或者硬件上实现多个线程并发执行的技术. 具有多线程能力的计算机因有硬件支持而能够在同一时间执行多个线程,提升性能. 并发和并行[理解] 并行:在同一时刻, ...
- Java 生产者消费者模式详细分析
*/ .hljs { display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; } .hl ...
- 基于Java 生产者消费者模式(详细分析)
Java 生产者消费者模式详细分析 本文目录:1.等待.唤醒机制的原理2.Lock和Condition3.单生产者单消费者模式4.使用Lock和Condition实现单生产单消费模式5.多生产多消费模 ...
- Java多线程-同步:synchronized 和线程通信:生产者消费者模式
大家伙周末愉快,小乐又来给大家献上技术大餐.上次是说到了Java多线程的创建和状态|乐字节,接下来,我们再来接着说Java多线程-同步:synchronized 和线程通信:生产者消费者模式. 一.同 ...
随机推荐
- Locust入门
Locust入门 Locust是一款Python技术栈的开源的性能测试工具.Locust直译为蝗虫,寓意着它能产生蝗虫般成千上万的并发用户: Locust并不小众,从它Github的Star数量就 ...
- Go语言介绍(背景、特点)
一.go语言的背景 Go是一个开源的编程语言,它能让构造简单.可靠且高效的软件变得容易. Go(又称 Golang)是 Google 的 Rob Pike(罗勃.派克),Ken Thompson(肯· ...
- OpenCV 查找轮廓
本文将结合实例代码,介绍 OpenCV 如何查找轮廓.获取边界框. 代码: contours.py OpenCV 提供了 findContours 函数查找轮廓,需要以二值化图像作为输入.并指定些选项 ...
- Windows下Qt VS 打包程序 到他人电脑安装运行出现的问题
1.可能缺程序依赖的Qt动态库 ------> 使用Qt自带的windeployqt进入安装程序所在的文件夹内进行自动配置 将程序安装在C盘之外的盘,这样可以方便windeployqt ...
- python工业互联网应用实战18—前后端分离模式之jquery vs vue
前面我们分三章来说明了使用django template与jquery的差别,通过jquery如何来实现前后端的分离,同时再9章节使用vue.js 我们浅尝辄止的介绍了JQuery到vue的切换,由于 ...
- python_appium 之使用Appium Inspector定位工具进行元素识别,编写验证demo
一.前提条件 appium环境搭建完成,模拟器Genymotion 安装完成,且已经下载成功了模拟设备 二.元素识别操作步骤及demo 1.进入appium如下菜单 2.填写Desired Capab ...
- 28.qt quick-ListView高仿微信好友列表和聊天列表
1.视图模型介绍 在Qml中.常见的View视图有: ListView: 列表视图,视图中数据来自ListModel.XmlListModel或c++中继承自QAbstractItemModel或Q ...
- APP的闪退和无响应
1.app闪退(crash,崩溃):程序异常退出不再运行 闪退的原因: a.程序内部逻辑错误(因算法或网络连接引起的异常,或是为捕捉到的错误) b.系统自身异常:一般自定ROM或刷机后比较常见 c.运 ...
- APP测试的主要内容
一.功能性测试:依据需求相关的文档编写测试用例进行测试 二.兼容性测试 系统版本:Android,ios 分辨率 网络情况 可用工具:testin 三.安装,升级,卸载测试 首次安装,覆盖安装,卸载后 ...
- 五、SELinux安全防护
rwx 针对用户和组 SELinux 针对程序 targeted:定义网络程序规则 minimum:限制少量软件 mls:限制全部,没定义的全拒绝 [root@proxy ~]# vim ...