VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > Java教程 >
  • 什么是死锁?

问题

什么是死锁?请模拟写出一段 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();





出处:https://www.cnblogs.com/okokabcd/p/8669286.html


相关教程