Java 示例 - 解决死锁

  • 问题描述

    如何使用线程解决死锁?
  • 解决方案

    下面的例子演示了如何使用线程的概念来解决死锁。
    
    import java.util.*;
    import java.util.concurrent.*;
    import java.util.concurrent.locks.*;
    public class DeadlockDetectingLock extends ReentrantLock {
       private static List deadlockLocksRegistry = new ArrayList();
       private static synchronized void registerLock(DeadlockDetectingLock ddl) {
          if (!deadlockLocksRegistry.contains(ddl)) deadlockLocksRegistry.add(ddl);
       }
       private static synchronized void unregisterLock(DeadlockDetectingLock ddl) {
          if (deadlockLocksRegistry.contains(ddl)) deadlockLocksRegistry.remove(ddl);
       }
       private List hardwaitingThreads = new ArrayList();
       private static synchronized void markAsHardwait(List l, Thread t) {
          if (!l.contains(t)) l.add(t);
       }
       private static synchronized void freeIfHardwait(List l, Thread t) {
          if (l.contains(t)) l.remove(t);
       }
       private static Iterator getAllLocksOwned(Thread t) {
          DeadlockDetectingLock current;
          ArrayList results = new ArrayList();
          Iterator itr = deadlockLocksRegistry.iterator();
       
          while (itr.hasNext()) {
             current = (DeadlockDetectingLock) itr.next();
             if (current.getOwner() == t)results.add(current);
          } 
          return results.iterator();
       } 
       private static Iterator getAllThreadsHardwaiting(DeadlockDetectingLock l) {
          return l.hardwaitingThreads.iterator();
       } 
       private static synchronized boolean canThreadWaitOnLock (
          Thread t,DeadlockDetectingLock l) {
          
          Iterator locksOwned = getAllLocksOwned(t);
          while (locksOwned.hasNext()) {
             DeadlockDetectingLock current = (DeadlockDetectingLock) locksOwned.next();
             if (current == l)return false;
             Iterator waitingThreads = getAllThreadsHardwaiting(current);
          
             while (waitingThreads.hasNext()) {
                Thread otherthread = (Thread) waitingThreads.next();
                if (!canThreadWaitOnLock(otherthread, l)) {
                   return false;
                }
             }
          }
          return true;
       } 
       public DeadlockDetectingLock() {
          this(false, false);
       } 
       public DeadlockDetectingLock(boolean fair) {
          this(fair, false);
       } 
       private boolean debugging;
       public DeadlockDetectingLock(boolean fair, boolean debug) {
          super(fair);
          debugging = debug;
          registerLock(this);
       } 
       public void lock() {
          if (isHeldByCurrentThread()) {
             if (debugging)
             System.out.println("Already Own Lock");
             super.lock();
             freeIfHardwait(hardwaitingThreads, 
             Thread.currentThread());
             return;
          } 
          markAsHardwait(hardwaitingThreads, Thread.currentThread());
          if (canThreadWaitOnLock(Thread.currentThread(), this)) {
             if (debugging) System.out.println("Waiting For Lock");
             super.lock();
             freeIfHardwait(hardwaitingThreads, Thread.currentThread()); 
             
             if (debugging)System.out.println("Got New Lock");
          } else {
             throw new DeadlockDetectedException("DEADLOCK");
          }
       }
       public void lockInterruptibly() throws InterruptedException {
          lock();
       }
       public class DeadlockDetectingCondition implements Condition {
          Condition embedded;
          protected DeadlockDetectingCondition(ReentrantLock lock, Condition embedded) {
             this.embedded = embedded;
          } 
          public void await() throws InterruptedException {
             try {
                markAsHardwait(hardwaitingThreads, Thread.currentThread());
                embedded.await();
             }
             finally {
                freeIfHardwait(hardwaitingThreads, 
                Thread.currentThread());
             }
          } 
          public void awaitUninterruptibly() {
             markAsHardwait(hardwaitingThreads, Thread.currentThread());
             embedded.awaitUninterruptibly();
             freeIfHardwait(hardwaitingThreads, Thread.currentThread());
          } 
          public long awaitNanos(long nanosTimeout) throws InterruptedException {
             try {
                markAsHardwait(hardwaitingThreads, 
                Thread.currentThread());
                return embedded.awaitNanos(nanosTimeout);
             }
             finally {
                freeIfHardwait(hardwaitingThreads, 
                Thread.currentThread());
             }
          } 
          public boolean await(long time, TimeUnit unit) throws InterruptedException {
             try {
                markAsHardwait(hardwaitingThreads, Thread.currentThread());
                return embedded.await(time, unit);
             } 
             finally {
                freeIfHardwait(hardwaitingThreads, Thread.currentThread());
             } 
          }
          public boolean awaitUntil(Date deadline) throws InterruptedException {
             try {
                markAsHardwait(hardwaitingThreads, Thread.currentThread());
                return embedded.awaitUntil(deadline);
             } 
             finally {
                freeIfHardwait(hardwaitingThreads, Thread.currentThread());
             }
          } 
          public void signal() {
             embedded.signal();
          } 
          public void signalAll() {
             embedded.signalAll();
          }
       }
       public Condition newCondition() {
          return new DeadlockDetectingCondition(this, super.newCondition());
       }
       private static Lock a = new DeadlockDetectingLock(false, true);
       private static Lock b = new DeadlockDetectingLock(false, true);
       private static Lock c = new DeadlockDetectingLock(false, true);
       
       private static Condition wa = a.newCondition();
       private static Condition wb = b.newCondition();
       private static Condition wc = c.newCondition();
       private static void delaySeconds(int seconds) {
          try {
             Thread.sleep(seconds * 1000);
          } catch (InterruptedException ex) {}
       }
       private static void awaitSeconds(Condition c, int seconds) {
          try {
             c.await(seconds, TimeUnit.SECONDS);
          } catch (InterruptedException ex) {}
       }
       private static void testOne() {
          new Thread(new Runnable() {
             public void run() {
                System.out.println("thread one grab a");
                a.lock();
                delaySeconds(2);
                System.out.println("thread one grab b");
                b.lock();
                delaySeconds(2);
                a.unlock();
                b.unlock();
             }
          }).start();
          new Thread(new Runnable() {
             public void run() {
                System.out.println("thread two grab b");
                b.lock();
                delaySeconds(2);
                System.out.println("thread two grab a");
                a.lock();
                delaySeconds(2);
                a.unlock();
                b.unlock();
             }
          }).start();
       }
       private static void testTwo() {
          new Thread(new Runnable() {
             public void run() {
                System.out.println("thread one grab a");
                a.lock();
                delaySeconds(2) ;
                System.out.println("thread one grab b");
                b.lock();
                delaySeconds(10); 
                a.unlock();
                b.unlock();
             }
          }).start();
          new Thread(new Runnable() {
             public void run() {
                System.out.println("thread two grab b");
                b.lock();
                delaySeconds(2);
                System.out.println("thread two grab c");
                c.lock();
                delaySeconds(10);
                b.unlock();
                c.unlock();
             }
          }).start();
          new Thread(new Runnable() {
             public void run() {
                System.out.println("thread three grab c");
                c.lock();
                delaySeconds(4);
                System.out.println("thread three grab a");
                a.lock();
                delaySeconds(10);
                c.unlock();
                a.unlock();
             }
          }).start();
       }
       private static void testThree() {
          new Thread(new Runnable() {
             public void run() {
                System.out.println("thread one grab b");
                b.lock();
                System.out.println("thread one grab a");
                a.lock();
                delaySeconds(2);
                System.out.println("thread one waits on b");
                awaitSeconds(wb, 10);
                a.unlock();
                b.unlock();
             }
          }).start();
          new Thread(new Runnable() {
             public void run() {
                delaySeconds(1);
                System.out.println("thread two grab b");
                b.lock();
                System.out.println("thread two grab a");
                a.lock();
                delaySeconds(10);
                b.unlock();
                c.unlock();
             }
          }).start();
       }
       public static void main(String args[]) {
          int test = 1;
          if (args.length > 0) test = Integer.parseInt(args[0]);
          switch (test) {
             case 1:
                testOne();
                break;
             case 2:
                testTwo(); 
                break; 
             case 3:
                testThree();
                break;
             default:
                System.err.println("usage: java DeadlockDetectingLock [ test# ]");
          }
          delaySeconds(60);
          System.out.println("--- End Program ---");
          System.exit(0);
       }
    }
    class DeadlockDetectedException extends RuntimeException {
       public DeadlockDetectedException(String s) {
          super(s);
       }
    }
    
  • 结果

    上面的代码示例将产生以下结果。
    
    thread one grab a
    Waiting For Lock
    Got New Lock
    thread two grab b
    Waiting For Lock
    Got New Lock
    thread one grab b
    Waiting For Lock
    thread two grab a
    Exception in thread "Thread-1" 
    DeadlockDetectedException:DEADLOCK
       at DeadlockDetectingLock.
          lock(DealockDetectingLock.java:152)
       at java.lang.Thread.run(Thread.java:595)