关于java中死锁的总结
关于死锁,估计很多程序员都碰到过,并且有时候这种情况出现之后的问题也不是非常好排查,下面整理的就是自己对死锁的认识,以及通过一个简单的例子来来接死锁的发生,自己是做python开发的,但是对于死锁的理解一直是一种模糊的概念,也是想过这次的整理更加清晰的认识这个概念。
用来理解的例子是一个简单的生产者和消费者模型,这里是有一个生产者,有两个消费者,并且注意代码中使用notify方法的代码行
package study_java.ex11;import java.util.LinkedList; import java.util.List;public class PCDemo1 {public static void main(String[] args){Pool pool = new Pool();Producter p1 = new Producter(pool);p1.setName("p1");Consumer c1 = new Consumer(pool);Consumer c2 = new Consumer(pool);c1.setName("c1");c2.setName("c2");p1.start();c1.start();c2.start();} }class Pool{private List<Integer> list = new LinkedList<Integer>();private int Max = 1;public void addLast(int n){String name = Thread.currentThread().getName();synchronized (this){while (list.size() >= Max){try{System.out.println(name+".wait()");this.wait();}catch (Exception e){e.printStackTrace();}}System.out.println(name + "+" + n);list.add(new Integer(n));System.out.println(name + ".notify()");this.notify(); // 注意这里是调用的是notify方法 }}public int remove(){String name = Thread.currentThread().getName();synchronized (this){while (list.size() == 0){try{System.out.println(name + ".wait()");this.wait();}catch (Exception e){e.printStackTrace();}}System.out.println(name + "-" + 0);int no = list.remove(0);System.out.println(name + ".notify()");this.notify(); // 注意这里是调用的是notify方法return no;}}}// 生产者 class Producter extends Thread{private Pool pool;static int i = 1;public Producter(Pool pool){this.pool = pool;}public void run(){while (true){pool.addLast(i++);System.out.println("生产者生产了"+i+"号");}}}// 消费者 class Consumer extends Thread{private Pool pool;public Consumer(Pool pool){this.pool = pool;}public void run(){while (true){int no = pool.remove();System.out.println("消费者消费了"+no+"号");}}}
这段代码的运行效果是日志,在最后程序卡主不动了:
c1.wait() p1+1 p1.notify() c1-0 c1.notify() 消费者消费了1号 c1.wait() 生产者生产了2号 p1+2 p1.notify() c1-0 c1.notify() 消费者消费了2号 c1.wait() 生产者生产了3号 p1+3 p1.notify() c1-0 c1.notify() 消费者消费了3号 c1.wait() 生产者生产了4号 p1+4 p1.notify() c1-0 c1.notify() 消费者消费了4号 c1.wait() 生产者生产了5号 p1+5 p1.notify() c1-0 c1.notify() 消费者消费了5号 c1.wait() 生产者生产了6号 p1+6 p1.notify() 生产者生产了7号 c1-0 c1.notify() 消费者消费了6号 c1.wait() p1+7 p1.notify() 生产者生产了8号 p1.wait() c2-0 c2.notify() 消费者消费了7号 c2.wait() c1.wait() p1+8 p1.notify() 生产者生产了9号 p1.wait() c2-0 c2.notify() 消费者消费了8号 c2.wait() c1.wait()
对上面的出现卡主的情况进行分析,理解为啥会卡主:
从这次的执行效果可以看出第一次是c1抢到了执行权,但是这个时候pool是空
所以c1没有可以消费的对象,被放入到了等待队列
接着p1抢到了执行权,生产了1个,然后p1.notify(),这个时候等待队列里只有c1,所以c1被唤醒,c1消费了1个,然后c1.notify(), 这个时候等待队列也没有等待的,这个时候有被c1抢到了执行权,但是pool里没有可以消费的内容,所以c1.wait() 进入到等待队列
这个时候p1抢到执行权,生产了1个,然后p1.notify(),这个时候等待队列里只有c1,所以c1被唤醒,c1也抢到了执行权,消费了1个,然后c1.notify()
同样这个时候等待队列里没有等待的,c1这次又抢到了执行权,但pool里没有可以消费的内容,所以c1.wait(),进入到等待队列
p1 又抢到了执行权,生产1个,然后p1.notify(),这个时候等待队列里只有c1,所以c1被唤醒,c1也抢到了执行权,消费了1个,然后c1.notify()
同样这个时候等待队列里没有等待的,c1这次又抢到了执行权,但pool里没有可以消费的内容,所以c1.wait(),进入到等待队列
.......这种情况重复了几次
但是运行到下面这段的时候问题出现了:
p1+7 p1.notify() 生产者生产了8号 p1.wait() c2-0 c2.notify() 消费者消费了7号 c2.wait() c1.wait() p1+8 p1.notify() 生产者生产了9号 p1.wait() c2-0 c2.notify() 消费者消费了8号 c2.wait() c1.wait()
继续进行分析,中间重复的部分不做分析了,和前面的过程是一样的
这个时候等待队里里依然是c1 这个时候p1抢到了执行权,生产了1个,p1.notify() 这个时候等待队列里只有c1,所以c1被唤醒,但是c1没有抢过p1,p1自己又抢到了执行权,但是这个时候pool里面已经有内容,所以p1没有生产,p1.wait(),p1进入等待队列
这个时候c2抢到了执行权,c2消费1个,c2.notify() 这个时候等待队里是p1,p1被唤醒,但是这个时候c2抢到了执行权,但是pool没有内容可以消费所以c2.wait() 进入等待队列
接着c1抢到了执行权,同样pool没有可以消费的内容,c1.wait() 进入到等待队列
p1这个时候抢到了执行权,p1生产了1个,接着p1.notify() 这个时候等待队列里有c1和c2,但是只有一个会被唤醒,不管是哪个,结果没抢过p1,p1再次拿到执行权,但是这个时候pool已经有内容,所以p1.wait() p1进入等待队列
从下面是c2执行,可以看出刚才是c2被唤醒了,这个时候c2也拿到了执行权消费了1个。c2.notify() 等待队列里这个时候有c1 和p1 但是这个时候c2 自己抢到了执行权,但是没有可以消费的,c2.wait() c2 进入等待队列
不巧的是刚才抢到执行权的正好是c1,所以c1继续wait,再次进入等待队列
到这个时候p1 c1 c2 都进入等待队列里,都在等待唤醒,也就出现了程勋最后卡住不动的情况
解决的方法有两种:
第一种:
其实解决上面的方法也比较简单,就是把调用notify的地方全部换成notifyAll方法
notify和notifyAll的区别是,当执行notifyAll的时候会唤醒所有等待的线程,从而避免之前的都在等待队列等待的问题
第二种:
就是wait()的时候加上超时参数,不是像之前一直傻等,而是在超过既定的时间之后自己唤醒
关于java中死锁的总结相关推荐
- Java中死锁产生的原因及解决方法
一.什么是死锁 死锁就是指两个或两个以上的线程在执行过程中,由于竞争资源或者由于彼此通信而造成的现象,若无外力作用,他们都无法推进下去. 简单来说就是A和B若同时都有一个资源,在此之外还想拥有对方的资 ...
- java中死锁_关于java中死锁的总结
关于死锁,估计很多程序员都碰到过,并且有时候这种情况出现之后的问题也不是非常好排查,下面整理的就是自己对死锁的认识,以及通过一个简单的例子来来接死锁的发生,自己是做python开发的,但是对于死锁的理 ...
- java产生死锁的主要原因_详解java中产生死锁的原因及如何避免
1. Java中导致死锁的原因 Java中死锁最简单的情况是,一个线程T1持有锁L1并且申请获得锁L2,而另一个线程T2持有锁L2并且申请获得锁L1,因为默认的锁申请操作都是阻塞的,所以线程T1和T2 ...
- java中产生死锁的原因及如何避免
转载自 https://blog.csdn.net/m0_38126177/article/details/78587845 1. Java中导致死锁的原因 Java中死锁最简单的情况是,一个线程T1 ...
- 浅谈JAVA中的死锁以及解决方案
目录 JAVA中死锁的定义: 死锁实例 1)实例业务场景 解决方案:定义锁的顺序,并且整个应用中都按照这个顺序来获取锁. 2)实例业务场景 解决方案: 总结造成死锁的原因: 如何防患? 定位死锁(解决 ...
- java多线程--死锁
1. Java中导致死锁的原因 Java中死锁最简单的情况是,一个线程T1持有锁L1并且申请获得锁L2,而另一个线程T2持有锁L2并且申请获得锁L1,因为默认的锁申请操作都是阻塞的,所以线程T1和T2 ...
- 浅析java中的死锁_Java学习笔记五十五(死锁问题)
多线程死锁问题. 我们知道,多线程可以改善系统的资源利用率,并且可以提高程序的运行效率.但是,多线程也带来了新的问题,即:死锁问题. 1.死锁的概念 死锁可以理解为多个线程为了争夺同一个资源,而出现互 ...
- java 死锁 内存消耗_详解Java中synchronized关键字的死锁和内存占用问题
先看一段synchronized 的详解: synchronized 是 java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码. 一.当两个并 ...
- 阿里面试题:如何检测并避免 Java 中的死锁?
作者:Yujiaao 来源:https://segmentfault.com/a/1190000019962661 经典但核心Java面试问题之一. 如果你没有参与过多线程并发 Java 应用程序的编 ...
最新文章
- MySQL与MongoDB之SQL语法对比
- 使用动态代理,提高工作效率
- 2017-01-09
- 如何进行I/O评估、监控、定位和优化?
- Coursera自动驾驶课程第17讲:An Autonomous Vehicle State Estimator
- 三观碎一地:轮子天天见,车轮悖论却2000年无解?
- shell学习脚本-tomcat停止脚本
- 【初赛】排列组合的一点笔记
- html桌面程序实例spark,【01】Spark 简单实例
- 液晶显示器尺寸对照表_安徽CHARACTER液晶显示屏
- npp夜光数据介绍 viirs_NPP-VIIRS年度夜间灯光数据的合成方法与验证
- maven项目中:java.io.IOException: java.io.FileNotFoundException--- (文件名、目录名或卷标语法不正确。)
- 数据库视图效率低下一例
- 永洪报表工具_2020年度10大BI工具排行榜
- 微信小程序开发的基本用法
- python代码画乌龟_乌龟教你Python编程——“玫瑰花”是怎么画的!
- 201521123037 《Java程序设计》第6周学习总结
- Modbus通信模式有哪几种?各自的特点有哪些?
- 【路由器】TP Link TL-WR702N 迷你路由器为何无法进入管理后台
- 51Nod-TalkingData数据科学精英夏令营挑战赛-B-丢手绢
热门文章
- c语言删除结构体数组的数据库,结构体数组的删除问题
- controller requestparam不传参数空指针异常_看完这篇文章,让你轻松学会Java异常处理...
- spring boot 拦截器获取controller返回的数据_高级码农Spring Boot实战与进阶之过滤器和拦截器的使用及其区别...
- mybatis plus 多表查询_Mybatis 多表查询之一对多
- Java数据结构与算法:红黑树
- 如何查看别人(自己)电脑最近的浏览记录
- php大于等于符号怎么打出来_PHP常用的特殊运算符号(连续小于符号,三个小于符号,eot,eod,echo示例,print示例)...
- abaqus画一个球 python_简单几步,100行代码用Python画一个蝙蝠侠的logo
- Docker容器网络管理
- python time.time和time.clock_Python中time.clock和 time.time的对比探究