java并发编程如何预防死锁
在java并发编程领域已经有技术大咖总结出了发生死锁的条件,只有四个条件都发生时才会出现死锁:
1.互斥,共享资源X和Y只能被一个线程占用
2.占有且等待,线程T1已经取得共享资源X,在等待共享资源Y的时候,不释放共享资源X
3.不可抢占,其他线程不能强行抢占线程T1占有的资源
4.循环等待,线程T1等待线程T2占有的资源,线程T2等待线程T1占有的资源,就是循环等待
只要能破坏其中一个,就可以成功避免死锁的发生,因为对于共享资源我们要得就是互斥的效果,所以第一个条件是无法破坏的,所以可以从下面三个条件出手,具体实现方式:
1.对于“占用且等待”这个条件,我们可以一次性申请所有的资源,这样就不存在等待了
class Allocator{
//通过破坏占有且等待条件避免死锁现象的发生
private List<Object> als = new ArrayList<>();
//一次申请所有的资源
synchronized boolean apply(Object from, Object to){
if (als.contains(from) || als.contains(to)){
//只要存在一个账户被其他的业务锁定则无法完成转账业务
return false;
}else {
als.add(from);
als.add(to);
}
return true;
}
//归还资源
synchronized void free(Object from,Object to){
als.remove(from);
als.remove(to);
}
}
class Account {
//actr应该为单例
private Allocator actr;
private int balance;
//转账
void transfer(Account target, int amt){
//一次性申请转出和转入账户,直到成功
while (!actr.apply(this,target));
try{
//锁定转出账户
synchronized (this){
//锁定转入账户
synchronized (target){
if (this.balance > amt){
this.balance -= amt;
target.balance += amt;
}
}
}
}finally {
actr.free(this, target);
}
}
}
2.对于“不可抢占”这个条件,占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动释放它所占有的资源,这样不可抢占这个条件就破坏掉了
3.对于“循环等待”这个条件,可以靠按序申请资源来预防,所谓按序申请,是指资源是有线性顺序的,申请的时候可以先申请资源序号小的,再申请资源序号大的,这样线性化后自然就不存在循环了
class Accounts{
private int id;
private int balance;
//转账
void transfer(Accounts target,int amt){
Accounts left = this;
Accounts right = target;
if (this.id > target.id){
left = target;
right = this;
}
//锁定序号小的账户
synchronized (left){
//锁定序号大的账户
synchronized (right){
if (this.balance > amt){
this.balance -= amt;
target.balance += amt;
}
}
}
}
}
java并发编程如何预防死锁的更多相关文章
- Java并发编程实战 04死锁了怎么办?
Java并发编程文章系列 Java并发编程实战 01并发编程的Bug源头 Java并发编程实战 02Java如何解决可见性和有序性问题 Java并发编程实战 03互斥锁 解决原子性问题 前提 在第三篇 ...
- 【Java并发编程】:死锁
当线程需要同时持有多个锁时,有可能产生死锁.考虑如下情形: 线程A当前持有互斥所锁lock1,线程B当前持有互斥锁lock2.接下来,当线程A仍然持有lock1时,它试图获取lock2,因为线程B正持 ...
- Java并发编程实战 05等待-通知机制和活跃性问题
Java并发编程系列 Java并发编程实战 01并发编程的Bug源头 Java并发编程实战 02Java如何解决可见性和有序性问题 Java并发编程实战 03互斥锁 解决原子性问题 Java并发编程实 ...
- Java并发编程原理与实战十一:锁重入&自旋锁&死锁
一.锁重入 package com.roocon.thread.t6; public class Demo { /* 当第一个线程A拿到当前实例锁后,进入a方法,那么,线程A还能拿到被当前实例所加锁的 ...
- java并发编程笔记(八)——死锁
java并发编程笔记(八)--死锁 死锁发生的必要条件 互斥条件 进程对分配到的资源进行排他性的使用,即在一段时间内只能由一个进程使用,如果有其他进程在请求,只能等待. 请求和保持条件 进程已经保持了 ...
- 【转】关于Java并发编程的总结和思考
一.前言 就是想学习Java并发编程了,所以转载一下这篇认为还不错的博客~ 二.正文 编写优质的并发代码是一件难度极高的事情.Java语言从第一版本开始内置了对多线程的支持,这一点在当年是非常了不起的 ...
- Java并发编程系列-(7) Java线程安全
7. 线程安全 7.1 线程安全的定义 如果多线程下使用这个类,不过多线程如何使用和调度这个类,这个类总是表示出正确的行为,这个类就是线程安全的. 类的线程安全表现为: 操作的原子性 内存的可见性 不 ...
- 【Java并发编程实战】----- AQS(三):阻塞、唤醒:LockSupport
在上篇博客([Java并发编程实战]----- AQS(二):获取锁.释放锁)中提到,当一个线程加入到CLH队列中时,如果不是头节点是需要判断该节点是否需要挂起:在释放锁后,需要唤醒该线程的继任节点 ...
- 【Java并发编程实战】-----“J.U.C”:ReentrantReadWriteLock
ReentrantLock实现了标准的互斥操作,也就是说在某一时刻只有有一个线程持有锁.ReentrantLock采用这种独占的保守锁直接,在一定程度上减低了吞吐量.在这种情况下任何的"读/ ...
随机推荐
- python 正则表达式 re.findall &re.finditer
语法: findall 搜索string,以列表形式返回全部能匹配的子串 re.findall(pattern, string[, flags]) finditer 搜索string,返回一个顺序访问 ...
- idea的类头注释和方法注释的编辑
一:配置类头注释 1:点击file,点击settings 2:点击editor,选择 file and code template ,然后看右侧部分点击include,之后选中File Header ...
- 第四周总结&第二次实验报告
实验二 Java简单类与对象 实验目的 掌握类的定义,熟悉属性.构造函数.方法的作用,掌握用类作为类型声明变量和方法返回值: 理解类和对象的区别,掌握构造函数的使用,熟悉通过对象名引用实例的方法和属性 ...
- Java设计模式——模板方法设计模式(abstract修饰)
解释: 一个抽象类中,有一个主方法,再定义 1...n 个方法,可以是抽象的,也可以是实际的方法,定义一个类,继承该抽象类,重写抽象方法,通过调用抽象类,实现对子类的调用. 解决的问题: 当功能内部一 ...
- BZOJ 4919 (树上LIS+启发式合并)
题面 给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点.每个点有一个权值v_i. 你需要将这棵树转化成一个大根堆.确切地说,你需要选择尽可能多的节点,满足大根堆的性质:对于任意两个点i, ...
- BZOJ 1875(DP+矩阵快速幂)
题面 传送门 分析 容易想到根据点来dp,设dp[i][j]表示到i点路径长度为j的方案数 状态转移方程为dp[i][k]=∑(i,j)∈Edp[j][k−1]" role="pr ...
- django的多语言国际化
介绍 Django 支持国际化,多语言.Django的国际化是默认开启的,如果您不需要国际化支持,那么您可以在您的设置文件中设置 USE_I18N = False,那么Django会进行一些优化,不加 ...
- Python2和Python3中的rang()不同之点
知道在python中rang()是一个有序的列表,在使用过程发现,Python2和Python3中的rang()不同之点,下面讲述不同之点 1,Python2 rang()用法 ->> r ...
- Hystrix (容错,回退,降级,缓存)
Hystrix熔断机制就像家里的保险丝一样,若同时使用高功率的电器,就会烧坏电路,这时候保险丝自动断开就有效的保护了电路.而我们程序中也同样是这样.例如若此时数据库压力太大速度很慢,此时还有不断的请求 ...
- asp.net Swiper 轮播动画
原文:https://blog.csdn.net/qq_39656138/article/details/90451289 官网:https://www.swiper.com.cn/api/index ...