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采用这种独占的保守锁直接,在一定程度上减低了吞吐量.在这种情况下任何的"读/ ...
随机推荐
- Git - 版本回溯
在git push的时候,有时候我们会想办法撤销git commit的内容 1.找到之前提交的git commit的id git log 找到想要撤销的id 2.git reset –hard id ...
- ios-wx.chooseImage选择图片后,在ios中选中的图片未显示
解决办法:微信引用1.2.0的版本 http://res.wx.qq.com/open/js/jweixin-1.2.0.js 我之前用的版本是:http://res.wx.qq.com/open/j ...
- GMS测试常用命令CTS>S&VTS
本文档介绍一下cts,gts,sts,vts,cts-on-gsi等测试的常用命令,基于Android9. [附件]Google官网的命令网页. 常用通用命令参数: 列出历史测试结果:l r 指定设备 ...
- 【Unity Shader】---Alpha Blending的意义
Alpha Blending 即Alpha混合 Blending 就是处理透明度的,处理光栅化最后阶段,显示在屏幕上的颜色 1 Blend Off 关闭alpha混合 2 混合公式:Blend Src ...
- Reverse Linked List(反转单向链表)
来源:https://leetcode.com/problems/reverse-linked-list Reverse a singly linked list. 递归方法:递归调用直到最后一个节点 ...
- RocketMQ的消息发送及消费
RocketMQ消息支持的模式: 消息支持的模式分为三种:NormalProducer(普通同步),消息异步发送,OneWay. 消息同步发送: 普通消息的发送和接收在前面已经演示过了,在前面的案例中 ...
- hibernate的get方法和load方法区别
读者需注意:Hibernate版本不同,运行机制不太一样,以下是hibernate3.x作为讲解 get方法: Hibernate会确认一下该id对应的数据是否存在,首先在session缓存中查找,然 ...
- 团队中的 Git 实践
转载自:https://segmentfault.com/a/1190000004963641 本文首发于欧雷流.由于我会时不时对文章进行补充.修正和润色,为了保证所看到的是最新版本,请阅读原文. 在 ...
- Nginx优化_定义对静态页面的缓存时间
修改Nginx配置文件,定义对静态页面的缓存时间 proxy ]# vim /usr/local/nginx/conf/nginx.conf server { listen 80; server_na ...
- ghci对haskell的类型推导
今天这篇文章分析一下ghci交互解释器对类型的推导. 假设有函数fn定义如下: let fn = map map 现在fn的类型是: map map :: [a -> b] -> [[a] ...