JAVA死锁:概念、原因、诊断、避免

参考书籍:《java高并发编程详解》

什么是死锁?

死锁,是指两个或两个以上的线程在执行过程中,由于资源竞争或彼此间通信或某原因造成的死循环而造成的一种(线程)阻塞的现象。若无外力作用,它们都将无法继续执行下去。此时成系统陷入了死锁状态或系统产生了死锁。

这些永远处于阻塞等待的进程称为死锁进程。

死锁产生的原因?

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:

JAVA死锁:概念、原因、诊断、避免_第1张图片

jconsole:

JAVA死锁:概念、原因、诊断、避免_第2张图片

如何避免死锁?

设置超时时间、或使用JUC包下的Lock相关类。

你可能感兴趣的:(java源码)