lock实现运行时死锁检测

java的多线程机制非常强大。其中死锁会导致程序无止境的等待,影响系统的正常运行,并且不是发生时立即被发现,一旦被发现定然是,系统出现了明显的功能性无法正常运行,甚至是系统崩溃。
下面我们讨论死锁的成因以及死锁的检测方法。

1、首先是系统运行时线程和锁之间的关系:
第一种情况:lock等待持有他们的thread将其释放。这些lock是由thread所持有,即thread获得了lock,其他的thread不能再获取到lock。

第二种情况:thread等待获取lock。如果此lock被其他的thead占用,那么此thread便只有等待其他thread将其释放。

2、死锁的产生
最简单的死锁产生的形式是:thread1 已经获取lock1,然后再去获取lock2,如果此时有thread2 已经获取了lock2 ,并且同时去获取lock1,那么就会发生死锁。

稍复杂的死锁的形式:
thread1:已经获得lock1
thread2:已经获得lock2,lock3。希望获得lock1
thread3:已经获得lock4。希望获得lock2

如果此时thread1 有需要获取到lock4,那么就可能会产生死锁。
3、死锁产生原因的分析:
从死锁的产生上,大家可以考虑到:如果将thread1 当成根节点,lock1是其子节点,thread2 是lock1的子节点,lock2,lock3 是thread2的子节点,同理:thread3 是lock2 的子节点,lock4 是thread3的子节点。如此可以看出thread与其相关的锁就是一个树结构,最上层是当前thread,其下是thread与lock交叉的分层。此树反应了一个thread所拥有的所有lock,然后是所有正在等待这些lock上thread,如此表示下去无论是直接还是间接,此树上的每个lock都在等待根thread最终将其释放,如此如果此thread需要对某个lock hard wait,它就不能在此树上,如此会产生一个循环,也就是死锁的成因。

4、下面的代码是实现了一个死锁检测的类,当产生死锁时抛出死锁异常。
注意:所有的锁的获取必须是lock形式,如果有synchrensed的锁形式,将不能被检测到。

下面这个例子展示了如何简单的检测到一个死锁。(当然效率是相当的低)

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 {
/**
*
*/
private static final long serialVersionUID = 1L;
// 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<DeadlockDetectingLock> deadlockLocksRegistry = new ArrayList<DeadlockDetectingLock>();

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<Thread> hardwaitingThreads = new ArrayList<Thread>();

private static synchronized void markAsHardwait(List<Thread> l, Thread t) {
if (!l.contains(t)) {
l.add(t);
}
}

private static synchronized void freeIfHardwait(List<Thread> 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<DeadlockDetectingLock> getAllLocksOwned(Thread t) {
DeadlockDetectingLock current;
ArrayList<DeadlockDetectingLock> results = new ArrayList<DeadlockDetectingLock>();

Iterator<DeadlockDetectingLock> 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<Thread> 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) {
//先获取t已经获取的lock锁list
Iterator<DeadlockDetectingLock> locksOwned = getAllLocksOwned(t);
while (locksOwned.hasNext()) {
DeadlockDetectingLock current = 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.
// t 获取 l 锁,如果此锁已经被需要获得l锁的线程获取,那么就是产生死锁的条件
if (current == l)
return false;
//获取(等待获取当前线程已经获得的current锁)的线程组
Iterator<Thread> 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();
//把当前线程从 wait list(无限等待获取该锁的线程列表)中移除,因为该线程已经获得该锁
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.
//如果当前线程没有获得当前锁,那么把当前线程加入到 wait list(无限等待获取该锁的线程列表)
markAsHardwait(hardwaitingThreads, Thread.currentThread());

//测试当前线程能否获取this当前锁
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 a b c 都被注册到 deadlockLocksRegistry 中
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);
}
}

以上代码是:java Thread 第三版 第六章的代码,详细请查看原始代码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值