关于多线程中的死锁问题
程序员文章站
2022-05-02 16:55:45
...
关于多线程中的死锁问题
锁是非常有用的工具,运用场景非常多,因为它使用起来非常方便,而且易于理解。但同时它也会带来一些困扰,那就是可能引起死锁。
什么是死锁?
百度百科中对于死锁的定义:死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。
死锁产生的四个条件
- 互斥条件:指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程用毕释放。
- 请求和保持条件:指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。
- 不剥夺条件:指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。
- 环路等待条件:指在发生死锁时,必然存在一个进程——资源的环形链,即进程集合
{P0,P1,P2,···,Pn}
中的P0正在等待一个P1占用的资源;P1正在等待P2占用的资源,……,Pn正在等待已被P0占用的资源。
来看一段代码,这段代码会引起死锁,使线程t1和线程t2互相等待对方释放锁。
package chapter1;
/**
* Created by Chen on 2017/9/24.
*/
public class DeadLockDemo {
private static String A = "A";
private static String B = "B";
public static void main(String[] args){
new DeadLockDemo().deadLock();
}
private void deadLock() {
Thread t1= new Thread(new Runnable() {
@Override
public void run() {
synchronized (A){
try{
Thread.currentThread().sleep(2000);
}catch (InterruptedException e){
e.printStackTrace();
}
synchronized (B){
System.out.println("1");
}
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (B){
synchronized (A){
System.out.println("2");
}
}
}
});
t1.start();
t2.start();
}
}
分析一下上面这段程序,当t1线程拿到A锁进入到程序后,睡眠了2秒,此时,t2线程访问程序,拿到B锁,接下来,它要获取A锁,但是A锁在t1线程中,没有释放。而t1线程醒来后要得到B锁才能继续运行,此时的B锁又在t2线程中,两个线程互相等待对方释放锁,就形成了死锁。
避免死锁的几个常见方法
- 避免一个线程同时获取多个锁。
- 避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源。
- 尝试使用定时锁,使用
lock.tryLock(timeout)
来替代使用内部锁机制。 - 对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况。
参考《Java并发编程的艺术》
上一篇: 关于python的多线程的Condition问题,制作了一个实验
下一篇: python中多线程