关于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中死锁的简单例子及其避免
死锁:当一个线程永远地持有一个锁,并且其他线程都尝试获得这个锁时,那么它们将永远被阻塞.比如,线程1已经持有了A锁并想要获得B锁的同时,线程2持有B锁并尝试获取A锁,那么这两个线程将永远地等待下去. ...
- Java中死锁的定位与修复
死锁应该可以说是并发编程中比较常见的一种情况,可以说如果程序产生了死锁那将会对程序带来致命的影响:所以排查定位.修复死锁至关重要: 我们都知道死锁是由于多个对象或多个线程之间相互需要对方锁持有的锁而又 ...
- 浅谈java中死锁问题
知识点:死锁的产生.死锁的实例 一:死锁的产生 我们在解决多线程共享资源的线程同步问题时,会使用synchronized关键字修饰方法或者通过Lock加锁方式修饰方法.代码块,防止多个线程访问统一资源 ...
- JAVA中关于同步与死锁的问题
java中当多个现成同时操纵同一资源的时候需要考虑同步的问题.如车站售票,不同售票点卖同一班次车票的时候就要同步,否则卖票会有问题.下面代码模拟车站卖票: class TicketSeller imp ...
- java多线程--死锁
1. Java中导致死锁的原因 Java中死锁最简单的情况是,一个线程T1持有锁L1并且申请获得锁L2,而另一个线程T2持有锁L2并且申请获得锁L1,因为默认的锁申请操作都是阻塞的,所以线程T1和T2 ...
- java之死锁
转载自 https://www.cnblogs.com/xiaoxi/p/8311034.html 一.死锁的定义 多线程以及多进程改善了系统资源的利用率并提高了系统 的处理能力.然而,并发执行也带来 ...
- 死锁线程探讨Java中的死锁现象
题记:写这篇博客要主是加深自己对死锁线程的认识和总结实现算法时的一些验经和训教,如果有错误请指出,万分感谢. 今天搞了一下Java的死锁机制,感到自己还是不怎么懂,所以就从一些简略的源代码中琢磨:我先 ...
- java中多线程产生死锁的原因以及解决意见
1. java中导致死锁的原因 多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放,而该资源又被其他线程锁定,从而导致每一个线程都得等其它线程释放其锁定的资源,造成了所有线程都无法正常结 ...
- java中的锁
java中有哪些锁 这个问题在我看了一遍<java并发编程>后尽然无法回答,说明自己对于锁的概念了解的不够.于是再次翻看了一下书里的内容,突然有点打开脑门的感觉.看来确实是要学习的最好方式 ...
随机推荐
- 深入理解JS防抖与节流
参考博客:JS防抖和节流,感谢作者的用心分享 日常开发过程中,滚动事件做复杂计算频繁调用回调函数很可能会造成页面的卡顿,这时候我们更希望把多次计算合并成一次,只操作一个精确点,JS把这种方式称为deb ...
- linux相关操作命令
1.复制文件:cp -r file ./src 2.删除文件:rm -rf file 3.解压文件:tar -xvf bianque.tar.gz
- C - Rikka with Badminton --- HDU 6425 快速幂加组合数学
---恢复内容开始--- 题目链接: https://vjudge.net/problem/1812693/origin 这题的mod运算很恶心,真的... 本题有正反两个思路,一个是正面求解其不能成 ...
- [jzoj]1417.数学题
Link https://jzoj.net/senior/#main/show/1417 Problem 当Alice在浏览数学书时,看到一个等式A=S,奇怪的是A和S并不相等.Alice发现可以通过 ...
- Django——缓存
设置缓存可采用CacheDemo中的中间件方法(https://www.cnblogs.com/siplips/p/9618034.html),对客户端浏览器缓存时间进行设定:也可采用下面的装饰器方法 ...
- 怎么样从多列的DataTable里取需要的几列
方法一: 也是广为人知的一种: YourDataTable.Columns.Remove("列名"); 但是这种情况只适合于去掉很少列的情况. 如果有很多列我却只要一两列呢,那就得 ...
- Flask-WTF表单的使用
使用flask的WTF表单 #! /usr/bin/env python # *-* coding: utf-8 *-* from flask import Flask, render_templat ...
- python部分面试- 测试维度
2. 软件测试的维度 1. 正确性:功能 正确 2. 健壮性: 意外的输入,不会崩溃 3. 性能: 大压力, 依然能工作 4. 可靠性: 长时间,不会崩溃 5. 易用性: 目标客户,都易用 6. 安全 ...
- KMSpico 无后门下载
MDL论坛 Windows Loader https://forums.mydigitallife.net/threads/windows-loader-download.58464/ KMS_V ...
- IE环境表单提交不跳转页面
<head> <base target="_self"></base> </head>