java并发-ReentrantLock源码分析

1关于可重入锁

ReentrantLock是基于AQS实现的可重入的同步工具类,它提供了两种同步器的实现即公平锁FairSync和非公平锁NonfairSync。它提供了一种无条件的、可轮询的、定时的以及可中断的锁获取操作,所有的加锁和解锁都是显式的。tryLock(),tryLock(long
,TimeUnit)分别提供了可轮询的、可定时的锁获取方式。 Lock()提供了无条件地轮询获取锁的方式。lockInterruptibly()提供了可中断的锁获取方式。 ReentrantLock它提供了两种锁机制,默认创建的是非公平锁。AQS的类结构图如下:

在公平锁上,线程是按照他们发出请求的顺序,如果锁被某个线程占用或者AQS队列中有等待线程,则该请求线程将进入队列排队直到获取锁。源码:

final void lock() {
     acquire(1);
}

非公平锁在请求获取锁时,直接尝试CAS操作获取锁,如果尝试失败才进行排队。在竞争激烈的情况下,非公平锁的性能高于公平锁的一个原因是:活动线程直接尝试获取锁的操作时间可能要比恢复一个阻塞线,并把锁分配给它的时间短的多(线程的唤醒操作需要额外的时间,从唤起到线程真正运行之间存在着严重的时延)。

 final void lock() {

            if (compareAndSetState(0, 1))

                setExclusiveOwnerThread(Thread.currentThread());

            else

                acquire(1);

          }

<span style="font-family:Calibri;">          </span>
2 NonfairSync锁

非公平锁的获取流程,允许插队,直接尝试CAS操作。

3 acquire(1)流程

acquire的获取流程是:先尝试获取锁,如果失败,则将当前节点从队尾添加进入AQS队列等待。操作返回值为空。如果线程在等待过程时中断标识为真,则中断当前线程。

4 tryAcquire(1)流程

tryAcquire(1)操作返回布尔类型,标识是否成功获取锁。如果空闲时CAS失败返回false,如果是当前线程持有锁,则说明是线程重入操作,将锁的重入次数累加,返回true.否则获取操作失败,返回false.

5 addWaiter入队流程

addWaiter将当前线程封装成一个队列节点Node,以for循环的方式重复尝试将节点插入AQS等待队列,直到操作成功返回该Node。AQS维持了一个链表,head和tail两个属性,初始时均为空。在添加第一个节点时会先创建一个虚拟的头节点(即new
Node()没有任何信息的节点),并将tail指向head。新节点从队尾以CAS原子操作插入,插入操作在for循环中,以保证线程无法获取锁的时候一定会被添加到等待队列中。

6 acquireQueued排队线程获取锁流程

获取失败的锁将会不断重试,直到线程被阻塞或者获取到锁为止。操作返回值是线程中断标识,如果在阻塞过程中被中断,则返回true给acquire操作,由其中断自己。为什么会有这种判断呢?我的理解:是为了保证线程阻塞过程中,中断信号不被淹没。如果在该线程被park后,其他线程向其发送了中断信号,则正常来说它是不能响应该请求的。这就是parkAndCheckInterrupt操作的必要,它在线程唤起时检查中断标志并通知该线程,由其去中断自己。(即acquire的selefIntrupt()操作)。

7 shouldParkAfterFailedAcquire

某个节点尝试获取锁操作,失败后,根据前驱节点的状态判断是否需要挂起该线程,该方法返回布尔类型值,标识当前节点是否需要被挂起。具体流程如下:

至此,锁获取操作流程介绍。ReentrantLock的lock操作的结果是,要么线程被挂起,要么循环轮询获取锁直到成功设置状态为1(占用状态),然后被移除排队队列。

8 unlock操作分析

锁释放操作只有当前线程是锁的持有者时才能进行,否则会抛出IllegalMonitorStateException。尝试释放锁,如果是成功且等待队列非空,则唤醒它的后继节点。唤醒后继节点的过程中,只有当其后继节点非空且非取消时,调用LockSupport的unpark唤醒,否则一直循环查找直到找到一个可唤起的后继节点为止。

时间: 2024-08-08 17:47:14

java并发-ReentrantLock源码分析的相关文章

Java并发编程 ReentrantLock 源码分析

ReentrantLock 一个可重入的互斥锁 Lock,它具有与使用 synchronized 方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大. 这个类主要基于AQS(AbstractOwnableSynchronizer)封装的 公平与非公平锁. 所谓公平锁就是指 在多个线程的争用下,这些锁倾向于将访问权授予等待时间最长的线程,换句话说也就是先被锁定的线程首先获得锁. 非公平锁正好相反,解锁时没有固定顺序. 让我们边分析源代码边学习如何使用该类 先来看一下构造参数,默认

Java并发编程之ReentrantLock源码分析

ReentrantLock介绍 从JDK1.5之前,我们都是使用synchronized关键字来对代码块加锁,在JDK1.5引入了ReentrantLock锁.synchronized关键字性能比ReentrantLock锁要差,而且ReentrantLock锁功能要比synchronized关键字功能强大. 特点 synchronized关键字和ReentrantLock锁都是重入锁,可重入锁是指当一个线程获取到锁后,此线程还可继续获得这把锁,在此线程释放这把锁前其他线程则不可获得这边锁.相比

ReentrantLock源码分析--jdk1.8

JDK1.8 ArrayList源码分析--jdk1.8LinkedList源码分析--jdk1.8HashMap源码分析--jdk1.8AQS源码分析--jdk1.8ReentrantLock源码分析--jdk1.8 ReentrantLock概述 ??1. ReentrantLock是独占锁.??2. ReentrantLock分为公平模式和非公平模式.??3. ReentrantLock锁可重入(重新插入) ReentrantLock源码分析 /** * @since 1.5 * @aut

java.io.BufferedOutputStream 源码分析

BufferedOutputStream  是一个带缓冲区到输出流,通过设置这种输出流,应用程序就可以将各个字节写入底层输出流中,而不必针对每次字节写入调用底层系统. 俩个成员变量,一个是存储数据的内部缓冲区,一个是缓冲区中的有效字节数. /** * The internal buffer where data is stored. */ protected byte buf[]; /** * The number of valid bytes in the buffer. This value

Java split方法源码分析

Java split方法源码分析 1 public String[] split(CharSequence input [, int limit]) { 2 int index = 0; // 指针 3 boolean matchLimited = limit > 0; // 是否限制匹配个数 4 ArrayList<String> matchList = new ArrayList<String>(); // 匹配结果队列 5 Matcher m = matcher(inp

【JAVA】ThreadLocal源码分析

ThreadLocal内部是用一张哈希表来存储: 1 static class ThreadLocalMap { 2 static class Entry extends WeakReference<ThreadLocal<?>> { 3 /** The value associated with this ThreadLocal. */ 4 Object value; 5 6 Entry(ThreadLocal<?> k, Object v) { 7 super(k)

Java并发系列[5]----ReentrantLock源码分析

在Java5.0之前,协调对共享对象的访问可以使用的机制只有synchronized和volatile.我们知道synchronized关键字实现了内置锁,而volatile关键字保证了多线程的内存可见性.在大多数情况下,这些机制都能很好地完成工作,但却无法实现一些更高级的功能,例如,无法中断一个正在等待获取锁的线程,无法实现限定时间的获取锁机制,无法实现非阻塞结构的加锁规则等.而这些更灵活的加锁机制通常都能够提供更好的活跃性或性能.因此,在Java5.0中增加了一种新的机制:Reentrant

Java并发包源码分析

并发是一种能并行运行多个程序或并行运行一个程序中多个部分的能力.如果程序中一个耗时的任务能以异步或并行的方式运行,那么整个程序的吞吐量和可交互性将大大改善.现代的PC都有多个CPU或一个CPU中有多个核,是否能合理运用多核的能力将成为一个大规模应用程序的关键. Java基础部分知识总结点击Java并发基础总结.Java多线程相关类的实现都在Java的并发包concurrent,concurrent包主要包含3部分内容,第一个是atomic包,里面主要是一些原子类,比如AtomicInteger.

Java - &quot;JUC&quot; Semaphore源码分析

Java多线程系列--"JUC锁"11之 Semaphore信号量的原理和示例 Semaphore简介 Semaphore是一个计数信号量,它的本质是一个"共享锁". 信号量维护了一个信号量许可集.线程可以通过调用acquire()来获取信号量的许可:当信号量中有可用的许可时,线程能获取该许可:否则线程必须等待,直到有可用的许可为止. 线程可以通过release()来释放它所持有的信号量许可. Java并发提供了两种加锁模式:共享锁和独占锁.前面LZ介绍的Reent