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);
    }
}

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。