ReentrantLock详解

  • 时间:
  • 浏览:3
  • 来源:uu快3漏洞_uu快3链接_公式

CANCELLED 

请况

这里仅给出流程图,上方会通过代码完正讲述你这一 流程。

ReentrantLock可需要支持多条件等待图片,真是现原理如下:每次调用newCondition()土措施,一定会创建原本ConditionObject对象,每个ConditionObject对象都可需要挂原本等待图片队列;完后 希望一同等待图片多个条件,只需要简单的多次调用newCondition创建多个条件对象就好了。

指向队列中前原本节点

假设3s中到了完后 ,Thread1被唤醒(挂起的完后 指定了时间,就说 等待图片时间到一定会被唤醒),此一定会将被委托人的请况改成CANCELLED,表示等待图片被从队列中移除;如下图所示:

-1

指向队列中后原本节点

完后 此时有新线程池池申请锁,没办法 在入队列过程中会顺便将地处CANCLE请况的节点移除。如下图所示:

Thread3申请锁时,完后 无法获取锁,就说 创建原本Node,很久加入到等待图片队列中;如下图所示:

  1. c) FairSync#tryAcquire
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
           // 完后

head的next节点对应的线程池池都不

当前线程池池,没办法


当前线程池池还可不还还可以了尝试获取锁,原本
要能保证按照获取所得顺序公平的获取锁。
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

关于synchronized的原理,可需要参考《互斥同步-锁》,地址为:https://yq.aliyun.com/articles/414939

  1. 2) tryAcquireNanos
    public final boolean tryAcquireNanos(int arg, long nanosTimeout)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        return tryAcquire(arg) ||
            doAcquireNanos(arg, nanosTimeout);
    }



类型

取消请况,同类完后 等待图片锁超时而取消的线程池池;地处你这一 请况的Node会被踢出队列,被GC回收





  1. 4) isOnSyncQueue

此土措施的主要逻辑如下:

Thread0执行完毕后,释放线程池池,将唤醒Head上方第原本请况为等待图片SIGNAL的节点对应的线程池池。

AbstractQueuedSynchronizer继承了AbstractOwnableSynchronizer,你这一 类还可不还还可以了原本变量:exclusiveOwnerThread,表示当前占用该锁的线程池池,很久提供了相应的get,set土措施。AQS使用此字段记录当前占有锁的线程池池。

int 

1

说明:先区分原本概念,本节中同步等待图片队列指的是指的是AQS中的FIFO的队列。条件等待图片队列指的是ConditionObject对象上的等待图片队列。

  1. 5) addWaiter

addWaiter是属于AbstractQueuedSynchronizer中的土措施。此土措施主要逻辑是:创建原本Node,与当前线程池池关联,很久尝试加入到FIFO队列的尾部。加入到FIFO队列时,完后 发现队列没办法 初始化过,即Head为空,没办法 先创建原本空的不与任何线程池池相关联的Node最为Head;很久将Node加入到队列尾部。

SIGNAL



-3

Provides a framework for implementing blocking locks and related synchronizers (semaphores, events, etc) that rely on first-in-first-out (FIFO) wait queues. 



每次原本线程池池释放锁完后 ,从Head开始 了了向后寻找,找到原本waitStatus是SIGNAL的节点,很久通过LockSupport.unpark唤醒被挂起的线程池池,被挂起的线程池池继续执行尝试上锁逻辑。新的线程池池尝试获取锁时,完后 获取还可不还还可以了锁,完后 创建原本Node并加入到队尾,很久将被委托人挂起,等待图片挂起时间到完后 等待图片被prev对应的节点唤醒。

说明:代码的中是从tail向head遍历查找waitStatus=SIGNAL的节点,但结果与这里说的是一样的,即最终也是找Head后的第原本waitStatus=SIGNAL的节点。见unparkSuccessor土措施

  1. 3) addConditionWaiter

此土措施的主要逻辑如下:

在AQS帕累托图亲戚朋友提到ReentrantLock中state记录的锁次数(当然也包括重入次数)。state=0代表当前没办法 线程池池持有锁。state>0代表加锁次数,第一次lock成功state=1,重入一次state++。





  1. 2) await

释放锁,挂起当前线程池池,等待图片一些线程池池发起唤醒信号(signal);被唤醒完后 重新获取锁。此土措施可需要认为和Object的wait等价。

公平锁和非公平锁的释放锁的过程是相同的,释放锁的流程图如下。

  1. 5) signal

简单来说是:唤醒线程池池。

Node的持有线程池池

下原本等待图片condition的Node

如下代码示例中,可需要想看 公平锁和非公平锁的第原本差别:非公平锁lock的第一步就说 尝试通过compareAndSetState(0, 1)获取锁,完后 他暂且求公平,就说 他上来就争抢锁。

等待图片请况

AQS使用原本FIFO的等待图片队列表示排队等待图片锁的线程池池,队列行态如图:



  1. Condition

Condition提供了原本 一种能力:线程池池获取锁完后 ,完后 条件不满足,挂起线程池池释放资源;完后 条件满足,则唤醒线程池池继续出理 。

属性名

假设初始请况,如下图所示:

队列头节点称作哨兵节点完后 哑节点,它不与任何线程池池关联,一些的节点与原本等待图片线程池池关联。

exclusiveOwnerThread代表持有所得线程池池信息,就说 一旦上锁成功,需要将exclusiveOwnerThread设置为当前线程池池。

创建ConditionObject对象,原本ConditionObject对象就说 原本普通的对象,没哪些地方地方有点硬的地方,就说 提供了await、signal等土措施,你这一 帕累托图将在上方完正分析。

请况值

Node

ReentrantLock是一种非常常见的临界区出理 手段,通过在执行代码前上锁保证同一时间还可不还还可以了原本线程池池能执行指定的代码块。ReentrantLock的行态与功能如下:

一些

描述

CONDITION

compareAndSetState(0, 1)土措施是基于CAS操作,尝试将state从0改为1。这是基于硬件指令集的原子操作,当且仅当state=0时将其修改为1。

亲戚朋友可需要想看 ,ReentrantLock默认构造器是非公平的。

使用在共享模式头Node有完后 地处你这一 请况, 表示锁的下一次获取可需要无条件传播

此土措施的主要逻辑如下:

prev

接下来亲戚朋友以原本简单的示例描述ReentrantLock的等待图片锁、释放锁的原理。为了方便描述,以下示例中节点和线程池池一一对应,同类Node1与Thread1对应,依次类推。

注意:新Node入队列一定会检查并删除被CANCELLED的节点;真是Node1等待图片图片时间到后被唤醒后,在将被委托人请况改为CANCELLED时,完后 发现被委托人是最后原本节点也会将Node1删除。

完后 公平锁、非公平锁的大帕累托图逻辑相同,就说 这里主要以非公平锁的源码来讨论。

关于线程池池、synchronized的更多内容,可需要参考《线程池池-基础知识》,地址为:https://yq.aliyun.com/articles/414908

释放锁,主要逻辑是:

事实上concurrent包内一些类都不 基于AQS构建,同类ReentrantLock,Semaphore,CountDownLatch,ReentrantReadWriteLock,FutureTask等。AQS出理 了在实现同步容器时设计的少许细节什么的什么的问题 。

next

注意,完后 线程池池获取锁失败,没办法 会在parkAndCheckInterrupt()土措施中被挂起。原本线程池池彻底释放锁资源完后 ,会唤醒head后的原本节点对应的线程池池,当某原本线程池池被唤醒完后 ,继续执行parkAndCheckInterrupt()土措施中LockSupport#park完后 的代码。

Node

-2



  1. ReentrantLock与synchronized对比
  1. 1 Synchronized

Synchronized是通过同步互斥来实现线程池池安全的;即同一时间还可不还还可以了有原本线程池池访问synchronized修饰的代码块或土措施。其行态与功能如下:

  1. 4) tryAcquire

此土措施是尝试获取锁。此时完后 state=0,说明所完后 被释放了,就说 可需要重新尝试上锁操作,即进行compareAndSetState(0, 1)操作;完后 state!=0,很久当前线程池池持有锁,没办法 重入,更新state,即state++。

AQS包含原本表示请况的字段state,ReentrantLock用它表示线程池池重入锁的次数,Semaphore用它表示剩余的许可数量,FutureTask用它表示任务的请况。对state变量值的更新都采用CAS操作保证更新操作的原子性。

完后 FIFO队列尚未初始化,没办法 先初始化;完后 完后 初始化了,没办法 尝试将node加入到队尾,失败则再试一次。

addWaiter是属于AbstractQueuedSynchronizer中的土措施。此土措施主要逻辑为:

表示你这一 Node在条件队列中,完后 等待图片某个条件而被阻塞

  1. 2 使用示例伪代码
    private ReentrantLock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();
    public void conditionWait() throws InterruptedException {
        // 完后

要能获取锁,没办法


直接往后执行,很久等待图片直到获取锁
        lock.lock();
        try {
            //资源是是不是完后

都准备好了?
            boolean resourceReady = false;
            if( !resourceReady ){
                //await会让当前线程池池释放其持有的锁并挂起
                condition.await();
            }
            // TODO 执行业务逻辑
        } finally {
            lock.unlock();
        }
    }

    public void conditionSignal() throws InterruptedException {
        // 完后

要能获取锁,没办法


直接往后执行,很久等待图片直到获取锁
        lock.lock();
        try {
            //资源是是不是完后

都准备好了?
            boolean resourceReady = true;
            if( resourceReady ){
                condition.signal();
            }
        } finally {
            lock.unlock();
        }
    }

Java中的CAS操作基本上都不 通过unsafe实现的,代码如下:

描述

ReentrantLock本质上是通过原本队列来完成同步的。完后 每个Node与原本线程池池关联,只需要做好对队列节点的同步出理 ,既可需要完成线程池池池的同步出理 。

相比于synchronized关键字,ReentrantLock等多的同类于亲戚朋友使用zookeeper实现的等待图片队列。Zookeeper的队列示例可需要参考博客《Zookeeper使用案例》地址为:https://yq.aliyun.com/articles/272103



非公平锁上锁主要流程如下所示:

Thread

  1. b) shouldParkAfterFailedAcquire

此土措施是用来判断是是不是应该挂起当前节点对应的线程池池。允许挂起的条件是:prev节点的waitStatus=SIGNAL。你这一 请况的意思是:prev节点对应的线程池池在释放锁完后 应该唤醒(unpack)node节点对应的线程池池。

非公平锁上锁主要流程如下所示:

AbstractQueuedSynchronizer简称AQS,是原本用于构建锁和相关同步器的框架,它依赖于FIFO的等待图片队列实现。见AbstractQueuedSynchronizer的描述:

  1. 4) unparkSuccessor

此土措施主要逻辑是:

初始请况

  1. 4 释放锁
  1. 1) unlock
    public void unlock() {
        sync.release(1);
    }

waitStatus

完后 prev节点waitStatus>0,即为CANCELLED请况时,需要将prev从队列中移除。重试此操作直到找到原本prve节点的请况不为CANCELLED。

nextWaiter

thread

PROPAGATE 

当且仅当以下两中请况,此土措施返回true。

acquire属于AbstractQueuedSynchronizer中的土措施;此土措施主要逻辑如下:

具体来说是:遍历等待图片队列,找出第原本等待图片被唤醒的节点Node,很久将它插入到同步等待图片队列尾部,很久就说 等待图片被唤醒(具体的过程与原本线程池池释放锁完后 一些线程池池获取所得过程相同)。

Node

以下是ReentrantLock的原本构造器,如下所示:

完后 prev节点waitStatus<=0(当然不包括SIGNAL请况),没办法 通过CAS操作设置waitStatus= SIGNAL

  1. 3) tryRelease

此土措施主要逻辑是:

AQS中维护了原本FIFO队列,用于记录等待图片的线程池池,上锁和释放锁的过程可需要认为是线程池池入队列和出队列的过程;获取还可不还还可以了锁,入队列等待图片;出队列时被唤醒。

你这一 帕累托图简要的介绍加锁、释放锁的流程,让亲戚朋友对ReentrantLock有原本整体的概念,上方将通过源码完正分析实现细节。

如流程图中所示,主要流程基本和非公平锁一致,有原本差别:

此土措施主要逻辑如下:

表示你这一 Node的继任Node被阻塞了,到需要要通知它

以下原本土措施时获取超时放弃锁的源码,其中主要逻辑在doAcquireNanos中,和前面讨论的“获取锁”帕累托图的(见acquireQueued土措施)主要区别在于:在循环中会检测等待图片时间是是不是完后 超过指定时间,完后 超过了,没办法 将Node的waitStatus改为CANCELLED请况。