Java线程 - 死锁(deadlock)
一、死锁
死锁是指这样一种状况。当多个线程竞争稀缺资源的时,由于他们相互等待获取对方线程所拥有的资源,大家都无法满足,从而都无法继续执行的情形。
P2进程拥有R1资源,但他正请求获取R2资源;而P1进程拥有R2资源,但他正请求R1资源。
1.1 Coffman条件--产生死锁的4个条件
如果一个系统中如下4种情形同时存在,则产生死锁情形的机会就会上升
- 互斥条件:进程要求对所分配的资源进行排它性控制,即在一段时间内某资源仅为一进程所占用
- 等待和保持条件:当进程因请求资源而阻塞时,对已获得的资源保持不放
- 不可剥夺条件:进程已获得的资源在未使用完之前,不能剥夺,只能在使用完时由自己释放
- 环路等待条件:在发生死锁时,必然存在一个进程--资源的环形链。更一般性来讲会有进程集合{P1,P2,P3....Pn},P1 申请P2获取的资源,P2申请P3资源....而Pn申请P1获取的资源,这样形成了一个闭环。
这4个条件即Coffman条件,由Edward G.Coffman, Jr先生于1971年首次提出。
二、java多线程死锁探测
从JDK1.5开始java.lang.management包提供了ThreadMXBean类,该类可用获取关于线程的各种各样的信息,包括探测线程的死锁。findMonitorDeadlockedThreads()方法返回long[],这些long[]表示发生死锁的线程的id。如果long[]数组等于null则表示没有发现死锁的线程。但这个方法只是监控object monitor的死锁,对于使用java.util.concurrent包的ownable synchronizer则无能为力。为此JDK1.6引入了一个新的方法findDeadlockedThreads()除了监控object monitor死锁外,同时还监控ownable synchronizer的死锁。
通过建立一个定期任务,让它使用ThreadMXBean定期核查是否存在死锁的线程,就可以解决线程死锁探测的问题。例如:
public class ThreadDeadlockDetector { //建立定期任务的调度器 private final Timer threadCheck = new Timer("ThreadDeadLockDector",true); private final Collection<Listener> listeners = new CopyOnWriteArraySet<Listener>(); private final ThreadMXBean mbean = ManagementFactory.getThreadMXBean(); private static final int DEFAULT_DEADLOCK_CHECK_PERIOD = 10000; public ThreadDeadlockDetector(){ this(DEFAULT_DEADLOCK_CHECK_PERIOD); } public ThreadDeadlockDetector(int deadlockCheckPeriod){ //建立一个定期核查的任务 threadCheck.schedule(new TimerTask(){ @Override public void run() { checkForDeadlocks(); } }, 10, deadlockCheckPeriod); } //一旦返现有死锁,就发出死锁报警 private void checkForDeadlocks() { long[] ids = findDeadlockedThreads(); if(ids != null && ids.length > 0) { Thread[] threads = new Thread[ids.length]; for(int i=0; i<threads.length; i++){ threads[i] = findMatchingThread(mbean.getThreadInfo(ids[i])); } fireDeadlockDetected(threads); } } //核查是否存在死锁 private long[] findDeadlockedThreads(){ if(mbean.isSynchronizerUsageSupported()){ return mbean.findDeadlockedThreads(); }else{ return mbean.findMonitorDeadlockedThreads(); } } private Thread findMatchingThread(ThreadInfo inf){ for(Thread thread:Thread.getAllStackTraces().keySet()){ if(thread.getId() == inf.getThreadId()){ return thread; } } throw new IllegalStateException("Deadlocked Thread not found"); } public boolean addListener(Listener l){ return listeners.add(l); } public boolean removeListener(Listener l){ return listeners.remove(l); } private void fireDeadlockDetected(Thread[] threads){ for(Listener l : listeners){ l.deallockDetected(threads); } } public interface Listener { void deallockDetected(Thread[] deadlockedThreads); } }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。