您的位置:首页 > 产品设计 > UI/UE

java并发编程--AbstractQueuedSynchronizer的lock()和lockInterruptibly()方法分析(五)

2015-08-13 11:30 791 查看
lock 与 lockInterruptibly比较区别在于:

lock 优先考虑获取锁,待获取锁成功后,才响应中断。

lockInterruptibly 优先考虑响应中断,而不是响应锁的普通获取或重入获取。

详细区别:

ReentrantLock.lockInterruptibly允许在等待时由其它线程调用等待线程的Thread.interrupt方法来中断等待线程的等待而直接返回,这时不用获取锁,而会抛出一个InterruptedException。
ReentrantLock.lock方法不允许Thread.interrupt中断,即使检测到Thread.isInterrupted,一样会继续尝试获取锁,失败则继续休眠。只是在最后获取锁成功后再把当前线程置为interrupted状态,然后再中断线程。


那lockInterruptibly是如何做到这一点的?

Java代码


public void lockInterruptibly() throws InterruptedException {

sync.acquireInterruptibly(1);

}

这里调用了AbstractQueuedSynchronizer.acquireInterruptibly方法。如果线程已被中断则直接抛出异常,否则则尝试获取锁,失败则doAcquireInterruptibly()

AbstractQueuedSynchronizer.acquireInterruptibly(int arg)

Java代码


/**

* Acquires in exclusive mode, aborting if interrupted.

* Implemented by first checking interrupt status, then invoking

* at least once {@link #tryAcquire}, returning on

* success. Otherwise the thread is queued, possibly repeatedly

* blocking and unblocking, invoking {@link #tryAcquire}

* until success or the thread is interrupted. This method can be

* used to implement method {@link Lock#lockInterruptibly}.

*

* @param arg the acquire argument. This value is conveyed to

* {@link #tryAcquire} but is otherwise uninterpreted and

* can represent anything you like.

* @throws InterruptedException if the current thread is interrupted

*/

public final void acquireInterruptibly(int arg) throws InterruptedException {

if (Thread.interrupted())

throw new InterruptedException();

if (!tryAcquire(arg))

doAcquireInterruptibly(arg);

}

AbstractQueuedSynchronizer.doAcquireInterruptibly大体上相当于前面的acquireQueued,关键的区别在于检测到interrupted后的处理,acquireQueued简单的记录下中断曾经发生,然后就象没事人似的去尝试获取锁,失败则休眠。而doAcquireInterruptibly检测到中断则直接退出循环,抛出InterruptedException异常。

AbstractQueuedSynchronizer.doAcquireInterruptibly(int arg)

Java代码


/**

* Acquires in exclusive interruptible mode.

* @param arg the acquire argument

*/

private void doAcquireInterruptibly(int arg)

throws InterruptedException {

final Node node = addWaiter(Node.EXCLUSIVE);

try {

for (;;) {

final Node p = node.predecessor();

/*

acquireQueued代码:

if (shouldParkAfterFailedAcquire(p, node) &&

parkAndCheckInterrupt())

interrupted = true;

*/

if (p == head && tryAcquire(arg)) {

setHead(node);

p.next = null; // help GC

return;

}

if (shouldParkAfterFailedAcquire(p, node) &&

parkAndCheckInterrupt())

break;

}

} catch (RuntimeException ex) {

cancelAcquire(node);

throw ex;

}

// Arrive here only if interrupted

// 取消获取锁尝试,将当前节点从等待队列中移除

cancelAcquire(node);

throw new InterruptedException();

}

在抛出异常之前,doAcquireInterruptibly还做了一件事情,cancelAcquire。cancelAcquire中有些细节值得玩味,参见代码中笔者注释。

AbstractQueuedSynchronizer.cancelAcquire(Node node)

Java代码


/**

* Cancels an ongoing attempt to acquire.

*

* @param node the node

*/

private void cancelAcquire(Node node) {

// Ignore if node doesn"t exist

if (node == null)

return;

node.thread = null;

// Skip cancelled predecessors

// 头节点一定不会是在等待状态,所以不会被cancel,所以这里一定能找到一个节点而不用担心null

Node pred = node.prev;

while (pred.waitStatus > 0)

node.prev = pred = pred.prev;

// Getting this before setting waitStatus ensures staleness

Node predNext = pred.next;

// Can use unconditional write instead of CAS here

node.waitStatus = Node.CANCELLED;

// If we are the tail, remove ourselves

if (node == tail && compareAndSetTail(node, pred)) {

compareAndSetNext(pred, predNext, null);

} else {

// If "active" predecessor found...

if (pred != head

&& (pred.waitStatus == Node.SIGNAL || compareAndSetWaitStatus(

pred, 0, Node.SIGNAL)) && pred.thread != null) {

// If successor is active, set predecessor"s next link

Node next = node.next;

if (next != null && next.waitStatus <= 0)

compareAndSetNext(pred, predNext, next);

} else {

/*这里如果不调用unparkSuccessor, 若在interrupted之后,执行到上面一句将waitStatus置CANCELLED之前,锁被释放,该线程被唤醒,则释放锁线程的unparkSuccessor不能起到预期作用,所以这里需要调用unparkSuccessor.即使此时持有锁的线程没有释放锁也不会有严重后果,被unpark的线程在获取锁失败后会继续park*/

unparkSuccessor(node);

}

node.next = node; // help GC

}

}

原文http://suo.iteye.com/blog/1331312
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: