什么是死锁?
问题
什么是死锁?请模拟写出一段 Java 死锁的核心代码?如何避免死锁?
答案
什么是死锁?
有一张银行卡,小A想往里存钱,小B想取钱,存钱和取钱需要卡和密码,现在小A有卡不知道密码,小B知道密码但是没有卡,陷入无限等待状态,这就是死锁。可用jstack命令进行分析。
死锁代码
public class ThreadDeadlock {
	public static void main(String[] args) throws InterruptedException {
		Integer obj1 = new Integer(1);
		Integer obj2 = new Integer(2);
		Integer obj3 = new Integer(3);
		Thread t1 = new Thread(new SyncThread(obj1, obj2), "t1");
		Thread t2 = new Thread(new SyncThread(obj2, obj3), "t2");
		Thread t3 = new Thread(new SyncThread(obj3, obj1), "t3");
		t1.start();
		t2.start();
		t3.start();
	}
}
class SyncThread implements Runnable {
	private Object obj1;
	private Object obj2;
	public SyncThread(Object o1, Object o2) {
		this.obj1 = o1;
		this.obj2 = o2;
	}
	@Override
	public void run() {
		String name = Thread.currentThread().getName();
		System.out.println(name + " acquiring lock on " + obj1);
		synchronized (obj1) {
			System.out.println(name + " acquired lock on " + obj1);
			work();
			System.out.println(name + " acquiring lock on " + obj2);
			synchronized (obj2) {
				System.out.println(name + " acquired lock on " + obj2);
				work();
			}
			System.out.println(name + " released lock on " + obj2);
		}
		System.out.println(name + " released lock on " + obj1);
		System.out.println(name + " finished execution.");
	}
	private void work() {
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}
输出结果:
t3 acquiring lock on 3
t3 acquired lock on 3
t2 acquiring lock on 2
t1 acquiring lock on 1
t1 acquired lock on 1
t2 acquired lock on 2    
t2 acquiring lock on 3 # t2得到资源2的锁等待资源3的锁
t3 acquiring lock on 1 # t3得到资源3的锁等待资源1的锁
t1 acquiring lock on 2 # t1得到资源1的锁等待资源2的锁
# 至此3个线程相互等待进入死锁
如何避免死锁
- 考虑加锁的顺序 每个人获取锁的顺序相同
- 避免无限期的等待,考虑加锁的时限 每个人持有锁而未访问到资源的超时时间
- 避免嵌套封锁
- 只对有请求的进行封锁
通过编程发现Java死锁
DeadlockHandler.java
import java.lang.management.ThreadInfo;
public interface DeadlockHandler {
	void handleDeadlock(final ThreadInfo[] deadlockedThreads);
}
DeadlockDetector.java
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class DeadlockDetector {
	private final DeadlockHandler deadlockHandler;
	private final long period;
	private final TimeUnit unit;
	private final ThreadMXBean mbean = ManagementFactory.getThreadMXBean();
	private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
	final Runnable deadlockCheck = new Runnable() {
		@Override
		public void run() {
			long[] deadlockedThreadIds = DeadlockDetector.this.mbean.findDeadlockedThreads();
			if (deadlockedThreadIds != null) {
				ThreadInfo[] threadInfos = DeadlockDetector.this.mbean.getThreadInfo(deadlockedThreadIds);
				DeadlockDetector.this.deadlockHandler.handleDeadlock(threadInfos);
			}
		}
	};
	public DeadlockDetector(final DeadlockHandler deadlockHandler, final long period, final TimeUnit unit) {
		this.deadlockHandler = deadlockHandler;
		this.period = period;
		this.unit = unit;
	}
	public void start() {
		this.scheduler.scheduleAtFixedRate(this.deadlockCheck, this.period, this.period, this.unit);
	}
}
DeadlockConsoleHandler.java
public class DeadlockConsoleHandler implements DeadlockHandler {
	@Override
	public void handleDeadlock(final ThreadInfo[] deadlockedThreads) {
		if (deadlockedThreads != null) {
			System.err.println("Deadlock detected!");
			Map<Thread, StackTraceElement[]> stackTraceMap = Thread.getAllStackTraces();
			for (ThreadInfo threadInfo : deadlockedThreads) {
				if (threadInfo != null) {
					for (Thread thread : Thread.getAllStackTraces().keySet()) {
						if (thread.getId() == threadInfo.getThreadId()) {
							System.err.println(threadInfo.toString().trim());
							for (StackTraceElement ste : thread.getStackTrace()) {
								System.err.println("t" + ste.toString().trim());
							}
						}
					}
				}
			}
		}
	}
}
使用:
// 在启动时启动一个周期性调用线程
DeadlockDetector deadlockDetector = new DeadlockDetector(new DeadlockConsoleHandler(), 5, TimeUnit.SECONDS);
deadlockDetector.start();

 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号