提示:看完这篇文章,你将会了解什么是死锁,死锁的必要条件,线上环境查看死锁的命令,死锁怎么避免
一、什么是死锁?
代码:
public class DeadLearn extends Thread{
private String lockA;
private String lockB;
public DeadLearn(String name,String lockA,String lockB) {
super(name);
this.lockA = lockA;
this.lockB= lockB;
}
public void run(){
synchronized (lockA){
System.out.println(this.getName()+" "+lockA);
try {
Thread.sleep(1000);
synchronized (lockB){
System.out.println(this.getName()+" "+lockB);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
String lockA="lockA";
String lockB="lockB";
Thread t1=new DeadLearn("t1:",lockA,lockB);
Thread t2=new DeadLearn("t2:",lockB,lockA);
t1.start();
t2.start();
t1.join();
t2.join();
}
}
运行结果
代码很简单,线程1持有了A锁,休眠1秒去拿B锁,线程2在线程1休眠的时候拿到了B锁,这样线程2和线程1就形成了死锁。
二、死锁必要条件
1.互斥条件
所谓互斥就是进程在某一时间内独占资源。
2.请求与保持条件
一个进程因请求资源而阻塞时,对已获得的资源保持不放。
3.请求与保持条件
一个进程因请求资源而阻塞时,对已获得的资源保持不放。
4.循环等待条件
若干进程之间形成一种头尾相接的循环等待资源关系。
这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之 一不满足,就不会发生死锁。
理解了死锁的原因,尤其是产生死锁的四个必要条件,就可以最大可能地避免、预防和 解除死锁。
三、死锁线上环境查看
用jstack +进程号查看线上环境死锁
四、避免死锁的办法
-
尽量使用 tryLock(long timeout, TimeUnit unit)的方法(
ReentrantLock
、ReentrantReadWriteLock
),设置超时时间,超时可以退出防止死锁。 -
尽量使用 Java. util. concurrent 并发类代替自己手写锁。
-
尽量降低锁的使用粒度,尽量不要几个功能用同一把锁。
-
尽量减少同步的代码块
synchronized
的循环引用。
那么我们用ReentrantLock
解决死锁
public class DeadLearn extends Thread{
private String lockA;
private String lockB;
private ReentrantLock lock;
public DeadLearn(String name,String lockA,String lockB,ReentrantLock lock) {
super(name);
this.lockA = lockA;
this.lockB= lockB;
this.lock=lock;
}
public void run(){
try {
lock.tryLock(2, TimeUnit.SECONDS);
System.out.println(this.getName()+" "+lockA);
Thread.sleep(1000);
lock.tryLock(2, TimeUnit.SECONDS);
System.out.println(this.getName()+" "+lockB);
lock.unlock();
lock.unlock();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
String lockA="lockA";
String lockB="lockB";
ReentrantLock lock=new ReentrantLock();
Thread t1=new DeadLearn("t1:",lockA,lockB,lock);
Thread t2=new DeadLearn("t2:",lockB,lockA,lock);
t1.start();
t2.start();
t1.join();
t2.join();
}
}