`
flylynne
  • 浏览: 373836 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

ReentrantLock 代码剖析之ReentrantLock.lockInterruptibly

 
阅读更多
source from:http://www.cnblogs.com/MichaelPeng/archive/2010/02/18/1669150.html
ReentrantLock.lockInterruptibly允许在等待时由其它线程调用等待线程的 Thread.interrupt方法来中断等待线程的等待而直接返回,这时不用获取锁,而会抛出一个InterruptedException。而 ReentrantLock.lock方法不允许Thread.interrupt中断,即使检测到Thread.isInterrupted,一样会继续尝试获取锁,失败则继续休眠。只是在最后获取锁成功后再把当前线程置为interrupted状态。

那 lockInterruptibly是如何做到这一点的?
   public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

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

AbstractQueuedSynchronizer.acquireInterruptibly(int arg)
复制代码
/**
     * 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)
复制代码
/**
     * 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();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    return;
                }
                /*
                acquireQueued代码:
           if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
*/
                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)
复制代码
/**
     * 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
    }
    }
分享到:
评论

相关推荐

    第15讲丨synchronized和ReentrantLock有什么区别呢?.html

    第15讲丨synchronized和ReentrantLock有什么区别呢?.html

    7、深入理解AQS独占锁之ReentrantLock源码分析(1).pdf

    根据给定文件的信息,我们可以深入理解AQS(AbstractQueuedSynchronizer)独占锁之ReentrantLock的源码分析及其实现原理。这不仅包括ReentrantLock本身的特性,还包括了其背后的AQS框架是如何工作的。 ### 一、管程...

    ReentrantLock源码的使用问题详解.docx

    《ReentrantLock源码详解与应用》 ReentrantLock,可重入锁,是Java并发编程中一个重要的锁实现,它提供了比synchronized更高级别的控制能力,包括公平性和非公平性选择。本文将深入探讨ReentrantLock的原理,特别...

    ReentrantLock代码剖析之ReentrantLock_lock

    在本文中,我们将深入分析`ReentrantLock`的`lock()`方法,理解其内部机制,包括锁的获取、释放以及公平性和非公平性的实现。 首先,`ReentrantLock`的`lock()`方法很简单,它只是调用了内部类`Sync`的`lock()`方法...

    synchronized ReentrantLock volatile Atomic 原理分析.docx

    《Java并发编程:synchronized、ReentrantLock、volatile与Atomic深度解析》 在Java多线程编程中,正确地管理共享资源是至关重要的。本文将深入探讨四种关键的并发控制机制:synchronized关键字、ReentrantLock(可...

    java ReentrantLock详解.docx

    `ReentrantLock`的`lockInterruptibly()`方法允许线程在等待锁时被中断,这在处理长时间等待的情况时非常有用。与`synchronized`不同,`synchronized`锁无法响应中断请求,除非释放锁。 4. **锁的状态检查**: - ...

    Java并发之ReentrantLock类源码解析

    Java并发之ReentrantLock类源码解析 ReentrantLock是Java并发包中的一种同步工具,它可以实现可重入锁的功能。ReentrantLock类的源码分析对理解Java并发机制非常重要。本文将对ReentrantLock类的源码进行详细分析,...

    Java中ReentrantLock的使用.docx

    尽管如此,ReentrantLock仍然有其独特之处,比如它可以提供公平锁和非公平锁的选择,支持中断锁等待,以及更细粒度的控制线程间的唤醒与等待。 1. **Lock接口**: - `lock()`:获取锁,如果无法立即获取,线程会被...

    ReentrantLock源码分析

    ### ReentrantLock源码分析 #### 一、ReentrantLock简介 ReentrantLock是一个基于`AbstractQueuedSynchronizer`(AQS)实现的高级锁工具类。与传统的synchronized关键字相比,ReentrantLock提供了更多控制手段,比如...

    Lock、Synchoronized和ReentrantLock的使用

    下面对这三种机制进行详细的分析和比较。 一、Synchronized Synchronized 是 Java 中最基本的同步机制,它可以用来同步方法或代码块。Synchronized 的实现是基于锁机制的,它会锁定一个对象的监视器,以便防止其他...

    ReentrantLock与synchronized

    在Java多线程编程中,`ReentrantLock`和`synchronized`都是用于实现线程同步的重要工具,确保在并发环境中数据的一致性和正确性。两者虽然都能实现互斥访问,但在功能、性能以及使用场景上有所不同。下面我们将深入...

    22 到底哪把锁更适合你?—synchronized与ReentrantLock对比.pdf

    在Java中,有两种主要的锁机制:内置的`synchronized`关键字和显式的`ReentrantLock`类。这两者各有优劣,适用于不同的场景。下面我们将详细讨论它们的区别、性能、特性以及使用上的差异。 1. **功能对比**: - `...

    Java多线程之ReentrantLock与Condition - 平凡希 - 博客园1

    总之,`ReentrantLock`是Java并发编程中的强大工具,它提供了丰富的功能和灵活性,使得开发者能够根据具体需求调整锁的行为,提高并发代码的性能和安全性。在设计和实现多线程程序时,了解和正确使用`ReentrantLock`...

    简单聊聊Synchronized和ReentrantLock锁.docx

    相比之下,ReentrantLock(可重入锁)是Java并发包java.util.concurrent.locks中的一个类,提供了更细粒度的锁控制。ReentrantLock允许显式获取和释放锁,并且支持更丰富的锁原语,如公平锁、非公平锁、可中断锁、...

    java多线程系列(四)ReentrantLock的使用.docx

    本篇文章将深入探讨`ReentrantLock`的使用,它是Java并发包`java.util.concurrent.locks`中的一个高级锁机制,相比传统的`synchronized`关键字,提供了更丰富的功能和更灵活的控制。 `ReentrantLock`全称为可重入锁...

    AQS和ReentrantLock.pdf

    AQS和ReentrantLock.pdf

    locks框架_ReentrantLock.pdf

    但是,需要注意的是,虽然ReentrantLock提供了更多的控制,但同时也增加了代码的复杂性,因此在选择使用时需要根据具体需求进行权衡。 总之,通过深入学习Locks框架,尤其是ReentrantLock,开发者可以更好地理解和...

    ReentrantLock解析

    《ReentrantLock深度解析》 在Java并发编程中,ReentrantLock是JDK提供的一个可重入互斥锁,它是java.util.concurrent.locks包下的核心类。与synchronized关键字相比,ReentrantLock提供了更高的灵活性,如尝试加锁...

    ReentrantLock.java

    ReentrantLock.java

    Java 多线程与并发(11-26)-JUC锁- ReentrantLock详解.pdf

    5. **锁的粒度**:ReentrantLock的锁可以更细粒度地控制,比如可以只锁住部分代码。 **源码分析** ReentrantLock类实现了Lock接口,提供了lock()、unlock()等方法。Sync类是内部抽象类,继承自AQS,它有两个子类...

Global site tag (gtag.js) - Google Analytics