天穹之边,浩瀚之挚,眰恦之美; 悟心悟性,虎头蛇尾,惟善惟道! —— 朝槿《朝槿兮年说》
写在结尾
在并发编程畛域,有两大外围问题:一个是互斥,即同一时刻只容许一个线程访问共享资源;另一个是同步,即线程之间如何通信、合作。
次要起因是,对于多线程实现实现并发,始终以来,多线程都存在2个问题:
- 线程之间内存共享,须要通过加锁进行管制,然而加锁会导致性能降落,同时简单的加锁机制也会减少编程编码难度
- 过多线程造成线程之间的上下文切换,导致效率低下
因而,在并发编程畛域中,始终有一个很重要的设计准则: “ 不要通过内存共享来实现通信,而应该通过通信来实现内存共享。”
简略来说,就是尽可能通过音讯通信,而不是内存共享来实现过程或者线程之间的同步。
关健术语
本文用到的一些要害词语以及罕用术语,次要如下:
- 并发(Concurrent): 在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行结束之间,且这几个程序都是在同一个处理机上运行。
- 并行(Parallel): 当零碎有一个以上CPU时,当一个CPU执行一个过程时,另一个CPU能够执行另一个过程,两个过程互不抢占CPU资源,能够同时进行。
- 信号量(Semaphore): 是在多线程环境下应用的一种设施,是能够用来保障两个或多个要害代码段不被并发调用,也是作零碎用来解决并发中的互斥和同步问题的一种办法。
- 信号量机制(Semaphores): 用来解决同步/互斥的问题的,它是1965年,荷兰学者 Dijkstra提出了一种行之有效的实现过程互斥与同步的办法。
- 管程(Monitor) : 个别是指治理共享变量以及对共享变量的操作过程,让它们反对并发的一种机制。
- 互斥(Mutual Exclusion):一个公共资源同一时刻只能被一个过程或线程应用,多个过程或线程不能同时应用公共资源。即就是同一时刻只容许一个线程访问共享资源的问题。
- 同步(Synchronization):两个或两个以上的过程或线程在运行过程中协同步调,按预约的先后秩序运行。即就是线程之间如何通信、合作的问题。
- 对象池(Object Pool): 指的是一次性创立出 N 个对象,之后所有的线程反复利用这 N 个对象,当然对象在被开释前,也是不容许其余线程应用的, 个别指保留实例对象的容器。
根本概述
在Java畛域中,咱们能够将锁大抵分为基于Java语法层面(关键词)实现的锁和基于JDK层面实现的锁。
在Java畛域中, 尤其是在并发编程畛域,对于多线程并发执行始终有两大外围问题:同步和互斥。其中:
- 互斥(Mutual Exclusion):一个公共资源同一时刻只能被一个过程或线程应用,多个过程或线程不能同时应用公共资源。即就是同一时刻只容许一个线程访问共享资源的问题。
- 同步(Synchronization):两个或两个以上的过程或线程在运行过程中协同步调,按预约的先后秩序运行。即就是线程之间如何通信、合作的问题。
针对对于这两大外围问题,利用管程是可能解决和实现的,因而能够说,管程是并发编程的万能钥匙。
尽管,Java在基于语法层面(synchronized 关键字)实现了对管程技术,然而从应用形式和性能上来说,内置锁(synchronized 关键字)的粒度绝对过大,不反对超时和中断等问题。
为了补救这些问题,从JDK层面对其“反复造轮子”,在JDK外部对其从新设计和定义,甚至实现了新的个性。
在Java畛域中,从JDK源码剖析来看,基于JDK层面实现的锁大抵次要能够分为以下4种形式:
- 基于Lock接口实现的锁:JDK1.5版本提供的ReentrantLock类
- 基于ReadWriteLock接口实现的锁:JDK1.5版本提供的ReentrantReadWriteLock类
- 基于AQS根底同步器实现的锁:JDK1.5版本提供的并发相干的同步器Semaphore,CyclicBarrier以及CountDownLatch等
- 基于自定义API操作实现的锁:JDK1.8版本中提供的StampedLock类
从浏览源码不难发现,在Java SDK 并发包次要通过AbstractQueuedSynchronizer(AQS)实现多线程同步机制的封装与定义,而通过Lock 和 Condition 两个接口来实现管程,其中 Lock 用于解决互斥问题,Condition 用于解决同步问题。
一.AQS根底同步器根本实践
在Java畛域中,同步器是专门为多线程并发设计的同步机制,次要是多线程并发执行时线程之间通过某种共享状态来实现同步,只有当状态满足这种条件时线程才往下执行的一种同步机制。
一个规范的AQS同步器次要有同步状态机制,期待队列,条件队列,独占模式,共享模式等五大外围因素组成。
在Java畛域中,JDK的JUC(java.util.concurrent.)包中提供了各种并发工具,然而大部分同步工具的实现基于AbstractQueuedSynchronizer类实现,其内部结构次要如下:
- 同步状态机制(Synchronization Status):次要用于实现锁(Lock)机制,是指同步状态,其要求对于状态的更新必须原子性的
- 期待队列(Wait Queue):次要用于寄存期待线程获取到的锁资源,并且把线程保护到一个Node(节点)外面和保护一个非阻塞的CHL Node FIFO(先进先出)队列,次要是采纳自旋锁+CAS操作来保障节点插入和移除的原子性操作。
- 条件队列(Condition Queue):用于实现锁的条件机制,个别次要是指替换“期待-告诉”工作机制,次要是通过ConditionObject对象实现Condition接口提供的办法实现。
- 独占模式(Exclusive Mode):次要用于实现独占锁,次要是基于动态外部类Node的常量标记EXCLUSIVE来标识该节点是独占模式
- 共享模式(Shared Mode):次要用于实现共享锁,次要是基于动态外部类Node的常量标记SHARED来标识该节点是共享模式
咱们能够失去一个比拟通用的并发同步工具根底模型,大抵蕴含如下几个内容,其中:
- 条件变量(Conditional Variable): 利用线程间共享的变量进行同步的一种工作机制
- 共享变量((Shared Variable)):个别指对象实体对象的成员变量和属性
- 阻塞队列(Blocking Queue):共享变量(Shared Variable)及其对共享变量的操作对立封装
- 期待队列(Wait Queue):每个条件变量都对应有一个期待队列(Wait Queue),外部须要实现入队操作(Enqueue)和出队操作(Dequeue)办法
- 变量状态形容机(Synchronization Status):形容条件变量和共享变量之间状态变动,又能够称其为同步状态
- 工作模式(Operation Mode): 线程资源具备排他性,因而定义独占模式和共享模式两种工作模式
综上所述,条件变量和期待队列的作用是解决线程之间的同步问题;共享变量与阻塞队列的作用是解决线程之间的互斥问题。
二. JDK显式锁对立概念模型
在并发编程畛域,有两大外围问题:一个是互斥,即同一时刻只容许一个线程访问共享资源;另一个是同步,即线程之间如何通信、合作。
综合Java畛域中的并发锁的各种实现与利用剖析来看,一把锁或者一种锁,基本上都会蕴含以下几个方面:
- 锁的同步器工作机制:次要是思考共享模式还是独享模式,是否反对超时机制,以及是否反对超时机制?
- 锁的同步器工作模式:次要是基于AQS根底同步器封装外部同步器,是否思考偏心/非偏心模式?
- 锁的状态变量机制: 次要锁的状态设置,是否共享状态变量?
- 锁的队列封装定义:次要是指期待队列和条件队列,是否须要条件队列或者期待队列定义?
- 锁的底层实现操作: 次要是指底层CL锁和CAS操作,是否须要思考自旋锁或者CAS操作实例对象办法?
- 锁的组合实现新锁: 次要是基于独占锁和共享锁,是否思考对应API自定义操作实现?
综上所述,大抵能够根据上述这些方向,咱们便能够分明️晓得Java畛域中各种锁实现的根本实践时和实现思维。
三.ReentrantLock(可重入锁)的设计与实现
在Java畛域中,ReentrantLock(可重入锁)是针对于Java多线程并发管制中对一个线程能够屡次对某个锁进行加锁操作,次要是基于内置的AQS根底形象队列同步器实现的一种并发管制工具类。
一般来说,对于同一个线程是否能够反复占有同一个锁对象的角度来分,大抵次要能够分为可重入锁与不可重入锁。其中:
- 可重入锁:一个线程能够屡次抢占同一个锁,也就意味着可能反对一个线程对资源的反复加锁,或者说,一个线程能够屡次进入同一个锁所同步的临界区代码块。
- 不可重入锁:一个线程只能抢占一次同一个锁,也就意味着在同一时刻只能有一个线程获取到锁,而其余获取锁的线程只能期待,只有领有锁的线程开释了锁后,其余的线程才可能获取锁。
ReentrantLock是JDK中显式锁一个次要基于Lock接口API实现的根底实现类,领有与内置锁(synchronized)雷同的并发性和内存语义,同时提供了限时抢占、可中断抢占等一些高级锁个性。
除此之外,ReentrantLock基于内置的AQS根底形象队列同步器实现,在线程参加锁资源竞争比拟强烈的场景下,能体现出比内置锁较佳的性能。
而且,ReentrantLock是一种独占锁,在独占模式下只能逐个应用锁,也就是说,任意时刻最多只会有一个线程持有锁的控制权。
1. 设计思维
ReentrantLock类最早是在JDK1.5版本提供的,从设计思维上来看,次要包含同步器工作模式,获取锁办法,开释锁办法以及定义Condition队列办法等4个外围因素。其中:
- 实现Lock接口 :次要基于Lock接口API实现对应办法,领有与内置锁(synchronized)雷同的并发性和内存语义,用于反对和解决解决互斥问题。
- 同步器工作模式:基于AQS根底形象队列同步器封装内置实现一个动态的内置同步器抽象类,而后基于这个抽象类别离实现了偏心同步器和非偏心同步器,用来指定和形容同步器工作模式是偏心模式还是非偏心模式。
- 偏心/非偏心模式:次要形容的是多个线程在同时获取锁时是否依照先到先得的程序获取锁,如果是则为偏心模式,否则为非偏心模式。
- 获取锁办法:次要定义了一个lock()办法来获取锁,示意如果锁曾经被其余线程占有或持有,其以后获取锁的线程则进入期待状态。
- 开释锁办法:次要定义了一个unlock()办法来开释锁,示意如果锁曾经被其余线程放弃或开释,其以后获取锁的线程则取得该锁。
- 定义Condition队列操作方法: 次要是基于Condition接口来定义一个办法实现锁的条件机制,用于反对线程的阻塞和唤醒性能即就是解决同步问题,也就是咱们说的线程间的通信形式。
- 定义期待队列操作方法: 次要是根据条件队列来时进行对应的操作,间接适配AQS根底同步器中对于期待队列的性能,保障获取锁的程序的公平性
2. 根本实现
在ReentrantLock类的JDK1.8版本中,对于ReentrantLock的根本实现如下:
public class ReentrantLock implements Lock, java.io.Serializable { private static final long serialVersionUID = 7373984872572414699 L; /** * ReentrantLock锁-定义反对同步器实现 */ private final Sync sync; /** * ReentrantLock锁-基于AQS定义反对同步器实现 */ abstract static class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = -5179523762034025860 L; /** * ReentrantLock锁-定义反对同步器Sync获取锁办法 */ abstract void lock(); //......其余办法代码 } /** * ReentrantLock锁-结构同步器默认工作模式(默认非偏心模式) */ public ReentrantLock() { sync = new NonfairSync(); } /** * ReentrantLock锁-结构同步器指定工作模式(可选偏心/非偏心模式) */ public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); } /** * ReentrantLock锁-获取锁(一般模式) */ public void lock() { sync.lock(); } /** * ReentrantLock锁-开释锁 */ public void unlock() { sync.release(1); } /** * ReentrantLock锁-创立锁的条件机制 */ public Condition newCondition() { return sync.newCondition(); } //......其余办法代码}
- 外部同步器:基于AQS根底同步器封装和定义了一个动态外部Sync抽象类,其中形象了一个内置锁lock()办法
- 同步器工作模式:提供了 2个构造方法,其中无参数构造方法示意的是默认的工作模式,有参数构造方法次要根据参数来实现指定的工作模式
- 获取锁: 次要是提供了lock()办法,调用的动态外部Sync抽象类内置锁lock()办法,而实质上是AQS同步器中的acquire()办法
- 开释锁: 次要是提供了unlock()办法,而实质上是调用的AQS同步器中的release()办法
- 创立条件队列: 次要是基于Condition接口定义了newCondition() 办法,调用的动态外部Sync抽象类ewCondition()办法,而实质上是调用的AQS同步器中的ConditionObject中的newCondition()办法
2.1 基于AQS同步器封装动态外部Sync抽象类
abstract static class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = -5179523762034025860L; /** * ReentrantLock锁-外部同步器Sync的内置加锁办法 */ abstract void lock(); /** * ReentrantLock锁-外部同步器Sync的非偏心获取锁 */ final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } /** * ReentrantLock锁-外部同步器Sync的尝试开释 */ protected final boolean tryRelease(int releases) { int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { free = true; setExclusiveOwnerThread(null); } setState(c); return free; } /** * ReentrantLock锁-外部同步器Sync的查看线程是否独占 */ protected final boolean isHeldExclusively() { // While we must in general read state before owner, // we don't need to do so to check if current thread is owner return getExclusiveOwnerThread() == Thread.currentThread(); } /** * ReentrantLock锁-外部同步器Sync的条件机制 */ final ConditionObject newCondition() { return new ConditionObject(); } /** * ReentrantLock锁-外部同步器Sync的判断锁持有者 */ final Thread getOwner() { return getState() == 0 ? null : getExclusiveOwnerThread(); } /** * ReentrantLock锁-外部同步器Sync的独占状态 */ final int getHoldCount() { return isHeldExclusively() ? getState() : 0; } /** * ReentrantLock锁-外部同步器Sync的是否被锁 */ final boolean isLocked() { return getState() != 0; } /** * ReentrantLock锁-外部同步器Sync的流化解决对象 */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); setState(0); // reset to unlocked state } }
- Sync类:FairSync偏心同步器和NonfairSync非偏心同步器的形象父类。
- 校验isHeldExclusively()办法: ReentrantLock锁是属于独占模式,须要以后锁持有线程与以后线程是否统一
- nonfairTryAcquire()办法: 个别次要用于非偏心模式获取锁,其外围是compareAndSetState办法和setExclusiveOwnerThread办法
- tryRelease()办法: 其偏心/非偏心模式都是通过ryRelease()来开释锁操作
- newCondition()办法: 基于AQS同步器的ConditionObject对象封装实现,提供给 ReentrantLock类应用
- 公有readObject()办法:对于输出的对象进行流化解决
特地须要留神的是,咱们须要重点关注nonfairTryAcquire()办法和tryRelease()办法,其中:
获取非偏心锁 nonfairTryAcquire()办法:次要是用于获取AQS的状态变量status,其默认取值范畴是0和1,其中,0示意未被加锁,1示意曾经被加锁
- 如果状态变量status=0,应用compareAndSetState办法进行CAS原子批改操作,把状态变量批改为1,并且通过setExclusiveOwnerThread设置以后线程为锁的持有线程
- 如果状态变量status=1,示意以后线程为锁的持有线程,正在进入锁重入操作,状态变量累加1,超过重入次数时,会抛出throw new Error("Maximum lock count exceeded")
开释锁tryRelease()办法:次要是查看以后线程是否为锁持有线程,随后AQS同步器状态变量减1,如果不是 throw new IllegalMonitorStateException()
- 如果状态变量status=0,示意锁曾经开释胜利,通过setExclusiveOwnerThread设置锁的持有线程为null,也就是置空锁的持有线程
- 如果状态变量status !=0, 须要状态变量递加1即可,直到锁曾经开释胜利
2.2 基于Sync抽象类封装FairSync偏心同步器
static final class FairSync extends Sync { private static final long serialVersionUID = -3000897897090466540L; /** * ReentrantLock锁-偏心模式-获取锁 */ final void lock() { acquire(1); } /** * ReentrantLock锁-偏心模式-尝试获取锁 */ protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { 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; } }
- 实现形式: 次要基于AQS封装的外部动态形象Sync同步类实现,应用的AQS的独占模式。
- 次要办法: 次要提供了lock()和tryAcquire()办法,其严格意义上来说,仅仅只是实现了tryAcquire()办法,然而最要害的应用hasQueuedPredecessors来保障了锁的公平性。
- 锁获取形式: 次要是采纳齐全通过队列来实现实现偏心机制,即就是查看是否存在期待队列,如果队列之中曾经存在其余线程,间接放弃操作。
2.3 基于Sync抽象类封装NonfairSync非偏心同步器
static final class NonfairSync extends Sync { private static final long serialVersionUID = 7316153563782823691L; /** * ReentrantLock锁-非偏心模式-获取锁 */ final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); } /** * ReentrantLock锁-非偏心模式-尝试获取锁 */ protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); } }
- 实现形式: 次要基于AQS封装的外部动态形象Sync同步类实现,应用的AQS的独占模式。
- 次要办法: 次要提供了lock()和tryAcquire()办法,其严格意义上来说,仅仅只是实现了tryAcquire()办法,间接调用了Sync同步类的nonfairTryAcquire()办法。
- 锁获取形式: 次要是采纳闯入策略来突破锁的偏心,也就是个别筹备获取锁的线程会先尝试获取锁,失败之后才进入队列中。
3. 具体实现
在ReentrantLock类的JDK1.8版本中,对于ReentrantLock的具体实现如下:
public class ReentrantLock implements Lock, java.io.Serializable { private static final long serialVersionUID = 7373984872572414699 L; /** Synchronizer providing all implementation mechanics */ private final Sync sync; /** * ReentrantLock锁-基于AQS定义反对同步器实现 */ abstract static class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = -5179523762034025860 L; /** * ReentrantLock锁-定义反对同步器Sync获取锁办法 */ abstract void lock(); //......其余办法代码 } /** * ReentrantLock锁-结构同步器默认工作模式(默认非偏心模式) */ public ReentrantLock() { sync = new NonfairSync(); } /** * ReentrantLock锁-结构同步器指定工作模式(可选偏心/非偏心模式) */ public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); } /** * ReentrantLock锁-获取锁(一般模式) */ public void lock() { sync.lock(); } /** * ReentrantLock锁-开释锁 */ public void unlock() { sync.release(1); } /** * ReentrantLock锁-创立锁的条件机制 */ public Condition newCondition() { return sync.newCondition(); } /** * ReentrantLock锁-获取锁(反对可中断机制) */ public void lockInterruptibly() throws InterruptedException { sync.acquireInterruptibly(1); } /** * ReentrantLock锁-尝试获取锁(一般模式) */ public boolean tryLock() { return sync.nonfairTryAcquire(1); } /** * ReentrantLock锁-尝试获取锁(反对超时) */ public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireNanos(1, unit.toNanos(timeout)); } /** * ReentrantLock锁-统计以后线程所持有数量 */ public int getHoldCount() { return sync.getHoldCount(); } /** * ReentrantLock锁-检测以后线程是否独占 */ public boolean isHeldByCurrentThread() { return sync.isHeldExclusively(); } /** * ReentrantLock锁-检测是否被加锁 */ public boolean isLocked() { return sync.isLocked(); } /** * ReentrantLock锁-检测是否偏心模式 */ public final boolean isFair() { return sync instanceof FairSync; } /** * ReentrantLock锁-获取以后锁持有线程 */ protected Thread getOwner() { return sync.getOwner(); } /** * ReentrantLock锁-检测轮询线程是否存在队列中 */ public final boolean hasQueuedThreads() { return sync.hasQueuedThreads(); } /** * ReentrantLock锁-检测线程是否存在队列中 */ public final boolean hasQueuedThread(Thread thread) { return sync.isQueued(thread); } /** * ReentrantLock锁-获取队列数量 */ public final int getQueueLength() { return sync.getQueueLength(); } /** * ReentrantLock锁-获取队列中的所有线程 */ protected Collection < Thread > getQueuedThreads() { return sync.getQueuedThreads(); } /** * ReentrantLock锁-检测存在条件队列是否入队状态 */ public boolean hasWaiters(Condition condition) { if (condition == null) throw new NullPointerException(); if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) throw new IllegalArgumentException("not owner"); return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject) condition); } /** * ReentrantLock锁-获取期待队列的长度 */ public int getWaitQueueLength(Condition condition) { if (condition == null) throw new NullPointerException(); if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) throw new IllegalArgumentException("not owner"); return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject) condition); } /** * ReentrantLock锁-获取期待队列的线程对象 */ protected Collection < Thread > getWaitingThreads(Condition condition) { if (condition == null) throw new NullPointerException(); if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) throw new IllegalArgumentException("not owner"); return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject) condition); }}
- 获取锁的办法:次要提供了个别模式lock()办法,反对可中断机制lockInterruptibly()办法,无参数tryLock()办法以及有参数的反对超时机制的tryLock(long timeout, TimeUnit unit)办法
- 开释锁的办法:次要是unlock()办法,间接调用是外部同步器中的release()办法
- 条件队列操作:次要提供了获取队列中的线程对象getQueuedThreads(),检测队列入队hasWaiters(Condition condition) 办法,以及
- 期待队列操作:次要提供了获取队列中的线程对象getWaitingThreads(Condition condition),检测队列入队hasQueuedThread(Thread thread) 办法,以及获取队列长度getQueueLength()办法和getWaitingThreads(Condition condition)办法
- 其余检测判断:次要有判断是否偏心模式isFair()办法,是否以后线程独占isHeldByCurrentThread()办法,以及是否加锁 isLocked()等
须要留神的是,在JDK1.8版本之后,对于ReentrantLock的实现有些轻微的变动,感兴趣的可自行参考相干版本的源码进行比照剖析。
综上所述,从肯定意义上讲,ReentrantLock是一种可重入的独占(互斥)锁,属于AQS根底形象队列同步器中独占模式孵化的产物,反对偏心模式与非偏心模式,默认采纳非偏心模式。
写在最初
通过对Java畛域中,JDK外部提供的各种锁的实现来看,始终围绕的外围次要还是基于AQS根底同步器来实现的,然而AQS根底同步器不是一种非它不可的技术标准规范,更多的只是一套技术参考指南。
然而,实际上,Java对于锁的实现与使用远远不止这些,还有相位器(Phaser)和交换器(Exchanger),以及在Java JDK1.8版本之前并发容器ConcurrentHashMap中应用的分段锁(Segment)。
不论是何种实现和利用,在Java并发编程畛域来讲,都是围绕线程平安问题的角度去思考的,只是针对于各种各样的业务场景做的具体的实现。
肯定意义上来讲,对线程加锁只是并发编程的实现形式之一,绝对于理论利用来说,Java畛域中的锁都只是一种繁多利用的锁,只是给咱们把握Java并发编程提供一种思维没,喋喋不休也不可能详尽。
到此为止,这算是对于Java畛域中并发锁的最终章,文中表述均为集体认识和集体了解,如有不到之处,忘请谅解也请给予批评指正。
最初,技术钻研之路任重而道远,愿咱们熬的每一个通宵,都撑得起咱们想在这条路上走上来的勇气,将来依然可期,与各位程序编程君共勉!