ReentrantLock: test for deadlocks : Deadlock « Threads « Java

Java
1. 2D Graphics GUI
2. 3D
3. Advanced Graphics
4. Ant
5. Apache Common
6. Chart
7. Class
8. Collections Data Structure
9. Data Type
10. Database SQL JDBC
11. Design Pattern
12. Development Class
13. EJB3
14. Email
15. Event
16. File Input Output
17. Game
18. Generics
19. GWT
20. Hibernate
21. I18N
22. J2EE
23. J2ME
24. JDK 6
25. JNDI LDAP
26. JPA
27. JSP
28. JSTL
29. Language Basics
30. Network Protocol
31. PDF RTF
32. Reflection
33. Regular Expressions
34. Scripting
35. Security
36. Servlets
37. Spring
38. Swing Components
39. Swing JFC
40. SWT JFace Eclipse
41. Threads
42. Tiny Application
43. Velocity
44. Web Services SOA
45. XML
Java Tutorial
Java Source Code / Java Documentation
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java » Threads » DeadlockScreenshots 
ReentrantLock: test for deadlocks
ReentrantLock: test for deadlocks

/*
Java Threads, 3rd Edition
By Scott Oaks, Henry Wong
3rd Edition September 2004 
ISBN: 0-596-00782-5

*/

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

// This is a very slow implementation of a ReentrantLock class and is not for
//   everyday usage. The purpose of this class is to test for deadlocks. The
// lock()
//   method now throws a DeadlockDetectedException, if a deadlock occurs. This
//   Alternate version has some production properties, including faster
//   deadlock check, full implementation of all lock methods, and configurable
//   options.
public class AlternateDeadlockDetectingLock extends ReentrantLock {
  // List of deadlock detecting locks.
  // This array is not thread safe, and must be externally synchronized
  //    by the class lock. Hence, it should only be called by static
  //    methods.
  private static List deadlockLocksRegistry = new ArrayList();

  private static synchronized void registerLock(
      AlternateDeadlockDetectingLock ddl) {
    if (!deadlockLocksRegistry.contains(ddl))
      deadlockLocksRegistry.add(ddl);
  }

  private static synchronized void unregisterLock(
      AlternateDeadlockDetectingLock ddl) {
    if (deadlockLocksRegistry.contains(ddl))
      deadlockLocksRegistry.remove(ddl);
  }

  // List of threads hard waiting for this lock.
  // This array is not thread safe, and must be externally synchronized
  //    by the class lock. Hence, it should only be called by static
  //    methods.
  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);
  }

  //
  // Deadlock checking methods
  //
  // Given a thread, return all locks that are already owned
  // Must own class lock prior to calling this method
  private static Iterator getAllLocksOwned(Thread t) {
    AlternateDeadlockDetectingLock current;
    ArrayList results = new ArrayList();

    Iterator itr = deadlockLocksRegistry.iterator();
    while (itr.hasNext()) {
      current = (AlternateDeadlockDetectingLockitr.next();
      if (current.getOwner() == t)
        results.add(current);
    }
    return results.iterator();
  }

  // Given a lock, return all threads that are hard waiting for the lock
  // Must own class lock prior to calling this method
  private static Iterator getAllThreadsHardwaiting(
      AlternateDeadlockDetectingLock l) {
    return l.hardwaitingThreads.iterator();
  }

  // Check to see if a thread can perform a hard wait on a lock
  // Must call synchronized version only...
  private static boolean canThreadWaitOnLock0(Thread t,
      AlternateDeadlockDetectingLock l) {
    Iterator locksOwned = getAllLocksOwned(t);
    while (locksOwned.hasNext()) {
      AlternateDeadlockDetectingLock current = (AlternateDeadlockDetectingLocklocksOwned
          .next();

      // Thread can't wait if lock is already owned. This is the end
      // condition
      //      for the recursive algorithm -- as the initial condition should be
      //      already tested for.
      if (current == l)
        return false;

      Iterator waitingThreads = getAllThreadsHardwaiting(current);
      while (waitingThreads.hasNext()) {
        Thread otherthread = (ThreadwaitingThreads.next();

        // In order for the thread to safely wait on the lock, it can't
        //   own any locks that have waiting threads that already owns
        //   lock. etc. etc. etc. recursively etc.
        if (!canThreadWaitOnLock0(otherthread, l)) {
          return false;
        }
      }
    }
    return true;
  }

  private static synchronized boolean canThreadWaitOnLock(Thread t,
      AlternateDeadlockDetectingLock l) {
    // Skip check if there is no owner
    // There is a race condition is the owner is null. However, it doesn't
    // matter.
    //     Testing for no owner ensures none of the threads in the thread wait
    //     tree will grab it later -- as all locks in the tree are owned.
    if (l.getOwner() == null) {
      return true;
    }
    return canThreadWaitOnLock0(t, l);
  }

  // Options: variable to control behavior
  //    FastFail: if set true, deadlock exception will thrown for every call
  // after
  //              first exception is detected
  //     CleanUp: if set true, lock will cleanup deadlock condition -- allowing
  //              for continued operation after failure. FastFail must be off.
  //    HWSWTime: # of seconds before a Softwait is to be considered as a
  // hardwait.
  //              Default is 60 seconds.
  private static boolean DDLFastFail = false;

  private static boolean DDLCleanUp = false;

  private static int DDLHWSWTime = 60;

  // Core Constructors
  //
  public AlternateDeadlockDetectingLock() {
    this(false, false);
  }

  public AlternateDeadlockDetectingLock(boolean fair) {
    this(fair, false);
  }

  private boolean debugging;

  public AlternateDeadlockDetectingLock(boolean fair, boolean debug) {
    super(fair);
    debugging = debug;
    registerLock(this);
  }

  private static boolean DDLdeadlockDETECTED = false;

  //
  // Core Methods
  //
  public void lock() {
    if (DDLFastFail && DDLdeadlockDETECTED) {
      throw new DeadlockDetectedException("EARILER DEADLOCK DETECTED");
    }

    // Note: Owner can't change if current thread is owner. It is
    //       not guaranteed otherwise. Other owners can change due to
    //       condition variables.
    if (isHeldByCurrentThread()) {
      if (debugging)
        System.out.println("Already Own Lock");
      super.lock();
      freeIfHardwait(hardwaitingThreads, Thread.currentThread());
      return;
    }

    // Note: The wait list must be marked before it is tested because
    //       there is a race condition between lock() method calls.
    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 {
      DDLdeadlockDETECTED = true;
      if (DDLCleanUp)
        freeIfHardwait(hardwaitingThreads, Thread.currentThread());
      throw new DeadlockDetectedException("DEADLOCK DETECTED");
    }
  }

  //
  // Note: It is debatable whether this is a hard or soft wait. Even if
  //       interruption is common, we don't know if the interrupting thread
  //       is also involved in the deadlock. In this alternate version, it
  //       will be treated as a hard wait.
  public void lockInterruptibly() throws InterruptedException {
    if (DDLFastFail && DDLdeadlockDETECTED) {
      throw new DeadlockDetectedException("EARILER DEADLOCK DETECTED");
    }

    // Note: Owner can't change if current thread is owner. It is
    //       not guaranteed otherwise. Other owners can change due to
    //       condition variables.
    if (isHeldByCurrentThread()) {
      if (debugging)
        System.out.println("Already Own Lock");
      try {
        super.lockInterruptibly();
      finally {
        freeIfHardwait(hardwaitingThreads, Thread.currentThread());
      }
      return;
    }

    // Note: The wait list must be marked before it is tested because
    //       there is a race condition between lock() method calls.
    markAsHardwait(hardwaitingThreads, Thread.currentThread());
    if (canThreadWaitOnLock(Thread.currentThread()this)) {
      if (debugging)
        System.out.println("Waiting For Lock");
      try {
        super.lockInterruptibly();
      finally {
        freeIfHardwait(hardwaitingThreads, Thread.currentThread());
      }
      if (debugging)
        System.out.println("Got New Lock");
    else {
      DDLdeadlockDETECTED = true;
      if (DDLCleanUp)
        freeIfHardwait(hardwaitingThreads, Thread.currentThread());
      throw new DeadlockDetectedException("DEADLOCK DETECTED");
    }
  }

  //
  // Note: It is debatable where is the point between a hard wait and a
  //      soft wait. Is it still a soft wait, if the timeout is large? As
  //      compromise, it is to be considered a hardwait if the timeout
  //      is larger than a specified time. Developers should modify this method
  //      as needed.
  public boolean tryLock(long time, TimeUnit unit)
      throws InterruptedException {
    if (DDLFastFail && DDLdeadlockDETECTED) {
      throw new DeadlockDetectedException("EARILER DEADLOCK DETECTED");
    }

    // Perform operation as a soft wait
    if (unit.toSeconds(time< DDLHWSWTime) {
      return super.tryLock(time, unit);
    }

    // Note: Owner can't change if current thread is owner. It is
    //       not guaranteed otherwise. Other owners can change due to
    //       condition variables.
    if (isHeldByCurrentThread()) {
      if (debugging)
        System.out.println("Already Own Lock");
      try {
        return super.tryLock(time, unit);
      finally {
        freeIfHardwait(hardwaitingThreads, Thread.currentThread());
      }
    }

    // Note: The wait list must be marked before it is tested because
    //       there is a race condition between lock() method calls.
    markAsHardwait(hardwaitingThreads, Thread.currentThread());
    if (canThreadWaitOnLock(Thread.currentThread()this)) {
      if (debugging)
        System.out.println("Waiting For Lock");
      try {
        return super.tryLock(time, unit);
      finally {
        freeIfHardwait(hardwaitingThreads, Thread.currentThread());
        if (debugging)
          System.out.println("Got New Lock");
      }
    else {
      DDLdeadlockDETECTED = true;
      if (DDLCleanUp)
        freeIfHardwait(hardwaitingThreads, Thread.currentThread());
      throw new DeadlockDetectedException("DEADLOCK DETECTED");
    }
  }

  // Note 1: Deadlocks are possible with any hard wait -- this includes
  //      the reacquitition of the lock upon return from an await() method.
  //      As such, condition variables will mark for the future hard
  //      wait, prior to releasing the lock.
  // Note 2: There is no need to check for deadlock on this end because
  //      a deadlock can be created whether the condition variable owns the
  //      lock or is reacquiring it. Since we are marking *before* giving
  //      up ownership, the deadlock will be detected on the lock() side
  //      first. It is not possible to create a new deadlock just by releasing
  //      locks.
  public class DeadlockDetectingCondition implements Condition {
    Condition embedded;

    protected DeadlockDetectingCondition(ReentrantLock lock,
        Condition embedded) {
      this.embedded = embedded;
    }

    // Note: The algorithm can detect a deadlock condition if the thead is
    //    either waiting for or already owns the lock, or both. This is why
    //    we have to mark for waiting *before* giving up the lock.
    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 nanosTimeoutthrows 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 deadlinethrows 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();
    }
  }

  // Return a condition variable that support detection of deadlocks
  public Condition newCondition() {
    return new DeadlockDetectingCondition(this, super.newCondition());
  }

  //
  // Testing routines here
  //
  // These are very simple tests -- more tests will have to be written
  private static Lock a = new AlternateDeadlockDetectingLock(false, true);

  private static Lock b = new AlternateDeadlockDetectingLock(false, true);

  private static Lock c = new AlternateDeadlockDetectingLock(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()// 2 threads deadlocking on grabbing 2 locks
      break;
    case 2:
      testTwo()// 3 threads deadlocking on grabbing 2 out of 3 locks
      break;
    case 3:
      testThree()// 2 threads deadlocking on 2 locks with CV wait
      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);
    }
}



           
       
Related examples in the same category
1. Demonstrates how deadlock can be hidden in a program
2. Another deadlock demo
3. Deadlock DetectingDeadlock Detecting
4. Using interrupt() to break out of a blocked thread.Using interrupt() to break out of a blocked thread.
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.