关于死锁,估计很多程序员都碰到过,并且有时候这种情况出现之后的问题也不是非常好排查,下面整理的就是自己对死锁的认识,以及通过一个简单的例子来来接死锁的发生,自己是做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中死锁的总结相关推荐

  1. Java中死锁产生的原因及解决方法

    一.什么是死锁 死锁就是指两个或两个以上的线程在执行过程中,由于竞争资源或者由于彼此通信而造成的现象,若无外力作用,他们都无法推进下去. 简单来说就是A和B若同时都有一个资源,在此之外还想拥有对方的资 ...

  2. java中死锁_关于java中死锁的总结

    关于死锁,估计很多程序员都碰到过,并且有时候这种情况出现之后的问题也不是非常好排查,下面整理的就是自己对死锁的认识,以及通过一个简单的例子来来接死锁的发生,自己是做python开发的,但是对于死锁的理 ...

  3. java产生死锁的主要原因_详解java中产生死锁的原因及如何避免

    1. Java中导致死锁的原因 Java中死锁最简单的情况是,一个线程T1持有锁L1并且申请获得锁L2,而另一个线程T2持有锁L2并且申请获得锁L1,因为默认的锁申请操作都是阻塞的,所以线程T1和T2 ...

  4. java中产生死锁的原因及如何避免

    转载自 https://blog.csdn.net/m0_38126177/article/details/78587845 1. Java中导致死锁的原因 Java中死锁最简单的情况是,一个线程T1 ...

  5. 浅谈JAVA中的死锁以及解决方案

    目录 JAVA中死锁的定义: 死锁实例 1)实例业务场景 解决方案:定义锁的顺序,并且整个应用中都按照这个顺序来获取锁. 2)实例业务场景 解决方案: 总结造成死锁的原因: 如何防患? 定位死锁(解决 ...

  6. java多线程--死锁

    1. Java中导致死锁的原因 Java中死锁最简单的情况是,一个线程T1持有锁L1并且申请获得锁L2,而另一个线程T2持有锁L2并且申请获得锁L1,因为默认的锁申请操作都是阻塞的,所以线程T1和T2 ...

  7. 浅析java中的死锁_Java学习笔记五十五(死锁问题)

    多线程死锁问题. 我们知道,多线程可以改善系统的资源利用率,并且可以提高程序的运行效率.但是,多线程也带来了新的问题,即:死锁问题. 1.死锁的概念 死锁可以理解为多个线程为了争夺同一个资源,而出现互 ...

  8. java 死锁 内存消耗_详解Java中synchronized关键字的死锁和内存占用问题

    先看一段synchronized 的详解: synchronized 是 java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码. 一.当两个并 ...

  9. 阿里面试题:如何检测并避免 Java 中的死锁?

    作者:Yujiaao 来源:https://segmentfault.com/a/1190000019962661 经典但核心Java面试问题之一. 如果你没有参与过多线程并发 Java 应用程序的编 ...

最新文章

  1. MySQL与MongoDB之SQL语法对比
  2. 使用动态代理,提高工作效率
  3. 2017-01-09
  4. 如何进行I/O评估、监控、定位和优化?
  5. Coursera自动驾驶课程第17讲:An Autonomous Vehicle State Estimator
  6. 三观碎一地:轮子天天见,车轮悖论却2000年无解?
  7. shell学习脚本-tomcat停止脚本
  8. 【初赛】排列组合的一点笔记
  9. html桌面程序实例spark,【01】Spark 简单实例
  10. 液晶显示器尺寸对照表_安徽CHARACTER液晶显示屏
  11. npp夜光数据介绍 viirs_NPP-VIIRS年度夜间灯光数据的合成方法与验证
  12. maven项目中:java.io.IOException: java.io.FileNotFoundException--- (文件名、目录名或卷标语法不正确。)
  13. 数据库视图效率低下一例
  14. 永洪报表工具_2020年度10大BI工具排行榜
  15. 微信小程序开发的基本用法
  16. python代码画乌龟_乌龟教你Python编程——“玫瑰花”是怎么画的!
  17. 201521123037 《Java程序设计》第6周学习总结
  18. Modbus通信模式有哪几种?各自的特点有哪些?
  19. 【路由器】TP Link TL-WR702N 迷你路由器为何无法进入管理后台
  20. 51Nod-TalkingData数据科学精英夏令营挑战赛-B-丢手绢

热门文章

  1. c语言删除结构体数组的数据库,结构体数组的删除问题
  2. controller requestparam不传参数空指针异常_看完这篇文章,让你轻松学会Java异常处理...
  3. spring boot 拦截器获取controller返回的数据_高级码农Spring Boot实战与进阶之过滤器和拦截器的使用及其区别...
  4. mybatis plus 多表查询_Mybatis 多表查询之一对多
  5. Java数据结构与算法:红黑树
  6. 如何查看别人(自己)电脑最近的浏览记录
  7. php大于等于符号怎么打出来_PHP常用的特殊运算符号(连续小于符号,三个小于符号,eot,eod,echo示例,print示例)...
  8. abaqus画一个球 python_简单几步,100行代码用Python画一个蝙蝠侠的logo
  9. Docker容器网络管理
  10. python time.time和time.clock_Python中time.clock和 time.time的对比探究