当前位置:网站首页>线程死锁——死锁产生的条件
线程死锁——死锁产生的条件
2022-07-08 00:43:00 【Archie_java】
什么是线程死锁
线程死锁是指由于两个或者多个线程互相持有对方所需要的资源,导致这些线程处于相互等待状态,若无外力作用,它们将无法继续执行下去。
造成死锁的原因可以概括成三句话:
- 当前线程拥有其他线程需要的资源
- 当前线程等待其他线程已拥有的资源
- 都不放弃自己拥有的资源
线程死锁产生的四个必要条件
- 互斥,共享资源 X 和 Y 只能被一个线程占用;
- 占有且等待,线程 T1 已经取得共享资源 X,在等待共享资源 Y 的时候,不释放共享资源 X;
- 不可抢占,其他线程不能强行抢占线程 T1 占有的资源;
- 循环等待,线程 T1 等待线程 T2 占有的资源,线程 T2 等待线程 T1 占有的资源,就是循环等待。
举个必然产生死锁的例子
public static void main(String[] args) {
Object a = new Object();
Object b = new Object();
// 线程1
new Thread(() -> {
synchronized (a) {
System.out.println("获得了A锁");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (b) {
}
}
}).start();
// 线程2
new Thread(() -> {
synchronized (b) {
System.out.println("获得了B锁");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (a) {
}
}
}).start();
}
上面的程序就是一个典型死锁的例子,为了保证死锁发生的几率,我这里在获得锁之后睡眠了1s。
线程1在获得A对象锁之后等了1s去尝试获取B对象锁,这时线程1是持有A对象锁的;线程2在获得B对象锁之后等待1s去尝试获得A对象锁,这时线程2是持有B对象锁的;就在它们彼此想获得对方的锁的时候,死锁发生了,并且一直持续下去。
如何避免死锁
上面提到只有这四个条件都发生时才会出现死锁,那么意思就是说,只要我们破坏其中一个,就可以成功预防死锁的发生。
- 破坏互斥:只有一把锁,这是形成死锁的最关键的原因。显然,如果我们能在两个线程跑之前,能给每个线程单独拷贝一份钥匙的副本,就能有效的避免死锁了。
- 占用且等待:
一次性申请所有的资源,这样就不存在等待了。
例如线程1一次性拿到A和B两个锁,线程2在获取锁的时候需要等待线程1释放锁,这样就避免了多线程互相占用等待的情况。 - 不可抢占:占用部分资源的线程进一步申请其他资源时,如果申请不到,可以
主动释放它占有的资源。
在上面的死锁代码中,我们使用了synchronized关键字,它是不能主动释放资源的,会造成线程一直阻塞,JUC提供了Lock解决这个问题。
显式使用Lock类中的定时tryLock功能来代替内置锁机制,可以检测死锁和从死锁中恢复过来。显式锁可以指定一个超时时限(Timeout),在等待超过该时间后tryLock就会返回一个失败信息,释放其拥有的资源,其他线程可以获取此资源避免死锁。 - 循环等待:如果一个线程需要一些锁,那么它必须按照确定的顺序获取锁。只有先获得了从顺序上排在前面的锁之后,才能获取后面的锁。
破坏循环条件很简单,只要线程之间不要出现交叉占用的情况即可,也就是说在在代码中尽量避免线程1保持A请求B,线程2保持B请求A,尽可能使他们请求的顺序一致,比如线程1请求的顺序是A、B,线程2请求的顺序也是A、B,这样自然就避免了循环等待的情况发生。
总结
死锁是一个比较头疼的问题,但是只要我们的代码规范,可以避免大多数情况下的死锁。还有避免死锁的经典算法是银行家算法,这里就不扩开介绍了。
在很多情况下,尤其是多线程编程中,我们要注意线程之间的资源是否存在互相竞争的情况,如果有,要及时规避死锁的风险。
死锁很多时候会发生在数据库操作中,例如长事务、并发条件下的共享锁升级等都会造成数据库死锁,后面有时间会专门针对数据库死锁讲一讲。
边栏推荐
- Ml backward propagation
- JVM memory and garbage collection-3-direct memory
- VIM use
- WPF 自定义 写实风 雷达图控件
- Nacos microservice gateway component +swagger2 interface generation
- 生命的高度
- Codeforces Round #649 (Div. 2)——A. XXXXX
- 日志特征选择汇总(基于天池比赛)
- leetcode 873. Length of Longest Fibonacci Subsequence | 873. 最长的斐波那契子序列的长度
- ArrayList源码深度剖析,从最基本的扩容原理,到魔幻的迭代器和fast-fail机制,你想要的这都有!!!
猜你喜欢

Remote Sensing投稿經驗分享

C语言-Cmake-CMakeLists.txt教程

Graphic network: uncover the principle behind TCP's four waves, combined with the example of boyfriend and girlfriend breaking up, which is easy to understand

云原生应用开发之 gRPC 入门

C语言-模块化-Clion(静态库,动态库)使用

burpsuite

JVM memory and garbage collection-3-runtime data area / method area

burpsuite

Sum of submatrix
![[reinforcement learning medical] deep reinforcement learning for clinical decision support: a brief overview](/img/45/5f14454267318bb404732c2df5e03c.jpg)
[reinforcement learning medical] deep reinforcement learning for clinical decision support: a brief overview
随机推荐
Many friends don't know the underlying principle of ORM framework very well. No, glacier will take you 10 minutes to hand roll a minimalist ORM framework (collect it quickly)
burpsuite
leetcode 873. Length of Longest Fibonacci Subsequence | 873. 最长的斐波那契子序列的长度
如何用Diffusion models做interpolation插值任务?——原理解析和代码实战
C语言-模块化-Clion(静态库,动态库)使用
Kwai applet guaranteed payment PHP source code packaging
Ml self realization / linear regression / multivariable
【SolidWorks】修改工程图格式
鱼和虾走的路
Node JS maintains a long connection
JVM memory and garbage collection-3-runtime data area / method area
WPF custom realistic wind radar chart control
Redisson分布式锁解锁异常
微软 AD 超基础入门
How to fix the slip ring
[recommendation system paper reading] recommendation simulation user feedback based on Reinforcement Learning
力扣5_876. 链表的中间结点
How to make enterprise recruitment QR code?
Introduction to Microsoft ad super Foundation
COMSOL --- construction of micro resistance beam model --- final temperature distribution and deformation --- addition of materials