什么是死锁?
死锁,是指两个或两个以上的线程在执行过程中,由于资源竞争或彼此间通信或某原因造成的死循环而造成的一种(线程)阻塞的现象。若无外力作用,它们都将无法继续执行下去。此时成系统陷入了死锁状态或系统产生了死锁。
这些永远处于阻塞等待的进程称为死锁进程。
死锁产生的原因?
1.交叉锁,例如,线程T1持有锁A,等待获取锁B;线程T2持有锁B,等待获取锁A;
public class DeadLock {
private final Object lock_A = new Object();
private final Object lock_B = new Object();
public void lockA() throws Exception {
synchronized (lock_A) {
System.err.println("获取锁A");
Thread.sleep(1000);
synchronized (lock_B) {
System.err.print("获取锁B");
}
}
}
public void lockB() throws Exception {
synchronized (lock_B) {
System.err.print("获取锁B");
Thread.sleep(1000);
synchronized (lock_A) {
System.err.println("获取锁A");
}
}
}
public static void main (String[] args) {
final DeadLock deadLock = new DeadLock();
new Thread(() -> {
while (true) {
try {
deadLock.lockA();
} catch (Exception e) {
e.printStackTrace();
}
}
}, "LOCK-A").start();
//
new Thread(() -> {
while (true) {
try {
deadLock.lockB();
} catch (Exception e) {
e.printStackTrace();
}
}
}, "LOCK-B").start();
}
}
2.内存不足,当并发请求系统可用内存时,如果此时内存不足,也会引起死锁。例如,线程T1和T2,执行某个任务,其中T1获取可用内存20MB,T2获取可用内存10MB,但是线程的执行单元至少需要30MB的可用内存,此时系统可用内存仅剩9MB,则每个线程都会等待其余线程释放资源,从而陷入死锁。
3.数据库锁引起,例如,某个线程对某行数据执行了for update事务,但是因为某种原因退出并未commit,从而导致后续线程请求该数据时,阻塞无限等待,陷入死锁。
4.死循环引起,例如,由于编码原因或某种异常处理不当,进入死循环,虽然查看线程堆栈信息不会发现任何死锁迹象,但是程序不工作,CPU占用率居高不下,系统进入假死状态,此类问题也可以称为“死锁”。(此类问题排查比较困难)
如何诊断死锁?
可以借助工具诊断,例如,jstack,jconsole,jProfiler(收费)。
运行上例代码,
jstack:
jconsole:
如何避免死锁?
设置超时时间、或使用JUC包下的Lock相关类。