java死锁介绍、源码实现及预防(含源码)
什么是死锁
死锁是 多个线程 之间 相互之间 持有 对方需要的资源,同时 又等待获取 对方持有资源的 一种尴尬状态;
比如:两个铁匠张铁匠和李铁匠, 都在打造 一把 武器,他们 都要使用 炉子和铁锤,但是这时候只有一个炉子和一个铁锤(只能同时满足一个人使用),在某一个时刻,张铁匠在使用 炉子 而 李铁匠 在使用铁锤 两个人都在等待 对方的工具使用完,进行下一个工序,(两个人都有一个特性:对方不闲下来 我就一直占着 这个工具),这样就造成了,两个人都不能完成下个工序,一直等待
死锁的条件
1、互斥使用,即当资源被一个线程使用(占有)时,别的线程不能使用
2、不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。
3、请求和保持,即当资源请求者在请求其他的资源的同时保持对原有资源的占有。
4、循环等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路。
代码实现
public class DeadLock {
public static void main(String[] args) {
DeadLockTest();
}
public static void DeadLockTest() {
// 创建两把 对象锁
Object o = new Object();
Object o1 = new Object();
// 此线程 首先 拿锁1 然后 拿锁2
new Thread(() -> {
worker(o, o1);
}, "worker1").start();
// 此线程 首先 拿锁2 然后 拿锁1
new Thread(() -> {
worker(o1, o);
}, "worker2").start();
}
/**
* 一个worker 完成一个 工作需要 获取两把锁
*
* @param lock0 锁1
* @param lock1 锁2
*/
public static void worker(Object lock0, Object lock1) {
synchronized (lock0) {
System.out.println("get com.studynote.lock:" + lock0.toString() + "============" + Thread.currentThread().getName() + " is running");
synchronized (lock1) {
System.out.println("get com.studynote.lock:" + lock1.toString() + "============" + Thread.currentThread().getName() + " is running");
}
}
}
}
如何预防死锁
给锁加过期时间
指定加锁顺序
使用算法
有序资源分配法
银行家算法
死锁检测
死锁检测是一个更好的死锁预防机制,它主要是针对那些不可能实现按序加锁并且锁超时也不可行的场景。
每当一个线程获得了锁,会在线程和锁相关的数据结构中(map、graph等等)将其记下。除此之外,每当有线程请求锁,也需要记录在这个数据结构中。