Java/Threads/Deadlock — различия между версиями
Admin (обсуждение | вклад) м (1 версия) |
|
(нет различий)
|
Текущая версия на 06:58, 1 июня 2010
Содержание
Another deadlock demo
public class AnotherDeadLock {
public static void main(String[] args) {
final Object resource1 = "resource1";
final Object resource2 = "resource2";
// t1 tries to lock resource1 then resource2
Thread t1 = new Thread() {
public void run() {
// Lock resource 1
synchronized (resource1) {
System.out.println("Thread 1: locked resource 1");
try {
Thread.sleep(50);
} catch (InterruptedException e) {
}
synchronized (resource2) {
System.out.println("Thread 1: locked resource 2");
}
}
}
};
// t2 tries to lock resource2 then resource1
Thread t2 = new Thread() {
public void run() {
synchronized (resource2) {
System.out.println("Thread 2: locked resource 2");
try {
Thread.sleep(50);
} catch (InterruptedException e) {
}
synchronized (resource1) {
System.out.println("Thread 2: locked resource 1");
}
}
}
};
// If all goes as planned, deadlock will occur,
// and the program will never exit.
t1.start();
t2.start();
}
}
Deadlock Detecting
/*
Java Threads, 3rd Edition
By Scott Oaks, Henry Wong
3rd Edition September 2004
ISBN: 0-596-00782-5
*/
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.locks.*;
//
// This is a very 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.
//
public class DeadlockDetectingLock 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(DeadlockDetectingLock ddl) {
if (!deadlockLocksRegistry.contains(ddl))
deadlockLocksRegistry.add(ddl);
}
private static synchronized void unregisterLock(DeadlockDetectingLock 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) {
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();
}
// 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(DeadlockDetectingLock l) {
return l.hardwaitingThreads.iterator();
}
// Check to see if a thread can perform a hard wait on a lock
private static synchronized boolean canThreadWaitOnLock(Thread t,
DeadlockDetectingLock l) {
Iterator locksOwned = getAllLocksOwned(t);
while (locksOwned.hasNext()) {
DeadlockDetectingLock current = (DeadlockDetectingLock) locksOwned
.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 = (Thread) waitingThreads.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 (!canThreadWaitOnLock(otherthread, l)) {
return false;
}
}
}
return true;
}
//
// Core Constructors
//
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);
}
//
// Core Methods
//
public void lock() {
// 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 {
throw new DeadlockDetectedException("DEADLOCK");
}
}
//
// 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. As a compromise, we"ll just
// not allow interrupts. This method is disabled.
public void lockInterruptibly() throws InterruptedException {
lock();
}
//
// Note: It is not necessary to override the tryLock() methods. These
// methods perform a soft wait -- there is a limit to the wait. It
// not possible to deadlock when locks are not waiting indefinitely.
//
// 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 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();
}
}
// 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 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(); // 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);
}
}
// : c13:DiningPhilosophers.java
// Demonstrates how deadlock can be hidden in a program.
// {Args: 5 0 deadlock 4}
// From "Thinking in Java, 3rd ed." (c) Bruce Eckel 2002
// www.BruceEckel.ru. See copyright notice in CopyRight.txt.
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
class Chopstick {
private static int counter = 0;
private int number = counter++;
public String toString() {
return "Chopstick " + number;
}
}
class Philosopher extends Thread {
private static Random rand = new Random();
private static int counter = 0;
private int number = counter++;
private Chopstick leftChopstick;
private Chopstick rightChopstick;
static int ponder = 0; // Package access
public Philosopher(Chopstick left, Chopstick right) {
leftChopstick = left;
rightChopstick = right;
start();
}
public void think() {
System.out.println(this + " thinking");
if (ponder > 0)
try {
sleep(rand.nextInt(ponder));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public void eat() {
synchronized (leftChopstick) {
System.out.println(this + " has " + this.leftChopstick
+ " Waiting for " + this.rightChopstick);
synchronized (rightChopstick) {
System.out.println(this + " eating");
}
}
}
public String toString() {
return "Philosopher " + number;
}
public void run() {
while (true) {
think();
eat();
}
}
}
public class DiningPhilosophers {
public static void main(String[] args) {
if (args.length < 3) {
System.err.println("usage:\n"
+ "java DiningPhilosophers numberOfPhilosophers "
+ "ponderFactor deadlock timeout\n"
+ "A nonzero ponderFactor will generate a random "
+ "sleep time during think().\n"
+ "If deadlock is not the string "
+ ""deadlock", the program will not deadlock.\n"
+ "A nonzero timeout will stop the program after "
+ "that number of seconds.");
System.exit(1);
}
Philosopher[] philosopher = new Philosopher[Integer.parseInt(args[0])];
Philosopher.ponder = Integer.parseInt(args[1]);
Chopstick left = new Chopstick(), right = new Chopstick(), first = left;
int i = 0;
while (i < philosopher.length - 1) {
philosopher[i++] = new Philosopher(left, right);
left = right;
right = new Chopstick();
}
if (args[2].equals("deadlock"))
philosopher[i] = new Philosopher(left, first);
else
// Swapping values prevents deadlock:
philosopher[i] = new Philosopher(first, left);
// Optionally break out of program:
if (args.length >= 4) {
int delay = Integer.parseInt(args[3]);
if (delay != 0)
new Timeout(delay * 1000, "Timed out");
}
}
} ///:~
class Timeout extends Timer {
public Timeout(int delay, final String msg) {
super(true); // Daemon thread
schedule(new TimerTask() {
public void run() {
System.out.println(msg);
System.exit(0);
}
}, delay);
}
} ///:~
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 = (AlternateDeadlockDetectingLock) itr.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 = (AlternateDeadlockDetectingLock) locksOwned
.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 = (Thread) waitingThreads.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 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();
}
}
// 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);
}
}
Using interrupt() to break out of a blocked thread.
//: c13:Interrupt.java
// Using interrupt() to break out of a blocked thread.
// From "Thinking in Java, 3rd ed." (c) Bruce Eckel 2002
// www.BruceEckel.ru. See copyright notice in CopyRight.txt.
import java.util.*;
class Blocked extends Thread {
public Blocked() {
System.out.println("Starting Blocked");
start();
}
public void run() {
try {
synchronized(this) {
wait(); // Blocks
}
} catch(InterruptedException e) {
System.out.println("Interrupted");
}
System.out.println("Exiting run()");
}
}
public class Interrupt {
static Blocked blocked = new Blocked();
public static void main(String[] args) {
new Timer(true).schedule(new TimerTask() {
public void run() {
System.out.println("Preparing to interrupt");
blocked.interrupt();
blocked = null; // to release it
}
}, 2000); // run() after 2000 milliseconds
}
} ///:~