Java并发-ReentrantLock源码分析
在Java5.0之前,在协调对共享对象的访问时可以使用的机制只有synchronized和volatile。Java 5.0增加了一种新的机制:ReentrantLock。ReentrantLock没有使用任何内建机制,仅仅从语言层面上实现了与synchronized相同的语义,而且还提供了跟多的功能,这一切都要归功于Java并发大师Doug Lea。在Java 5.0中,Doug Lea写了一个同步框架,AbstractQueuedSynchronizer(可以参考Doug Lea的论文:http://ifeve.com/aqs)。在AbstractQueuedSynchronizer(简称AQS)中,Doug Lea提供了两种管理状态的机制:独占模式和共享模式,在java.util.concurrency包里,很多类都是依赖与AQS构建的,关于AQS的源码,请参考《Java并发-AbstractQueuedSynchronizer源码分析》。现在我们看一下ReentrantLock内容。
ReentrantLock的结构
ReentrantLock是一个可重入的互斥锁,与内置的synchronized具有相同的语义,但是功能更强大。关于显式锁的用法我们不做介绍,重点是关注它是如何实现的。如Doug Lea所建议,ReentrantLock有一个内部类继承自AQS,就是Sync,锁的行为和实现都是由这个类来完成,ReentrantLock有一个Sync的引用。ReentrantLock支持公平和非公平两种策略,这两种策略分别由Sync的子类来实现。所以ReentrantLock的结构是这样的:
(1)ReentrantLock持有一个Sync的引用,具体的行为由Sync来完成,ReentrantLock的方法仅仅是简单的调用Sync的方法;
(2)Sync继承自AQS,它实现同步器的基本功能;
(3)Sync有两个子类,NonfairSync实现非公平策略下的独占锁,公平策略由FairSync来实现。
ReentrantLock有两个构造方法,默认是非公平策略,还有一个带参数以控制公平策略,这部分代码如下:
/** * 一个可重入的互斥锁,与内置的synchronized具有相同的语义,但是功能更强大 */ public class ReentrantLock implements Lock, java.io.Serializable { private static final long serialVersionUID = 7373984872572414699L; /** 所有的实现都有sync来实现 */ private final Sync sync; /** * 无参构造方法,使用非公平策略 */ public ReentrantLock() { sync = new NonfairSync(); } /**true 公平策略;false 非公平策略 */ public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); }从上面的代码片段中可以看出,如果使用公平模式,则创建FairSync对象,如果使用非公平策略,则使用NonfairSync对象。关于ReentrantLock的源码分析,重点在于如何获得锁,以及如何释放锁。
实现方式
AQS属于定义的模板方法,在获取状态和释放状态时,所有继承自AQS的类都是调用AQS的acquire(int)和release(int)方法,这两个方法的逻辑都已经写好,对于不同的实现,子类只需要重写tryAcquire和tryRelease方法即可。AQS的acquire和release方法如下:
/** * 以独占模式获取,忽略中断。 * 首先调用tryAcquire尝试获取,如果失败则加入队列 * 然后再次尝试获取,直到成功。 * 此方法可用于实现Lock.lock */ public final void acquire(int arg) { //首先尝试获取,失败后加入队列 //再次尝试获取,直到成功后再返回 if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); } /** * 释放独占的资源,此方法可用来实现Lock.unlock操作 */ public final boolean release(int arg) { if (tryRelease(arg)) { Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h); return true; } return false; }在AQS的内部维护着一个同步队列,如果当前线程获取不到状态,则进入同步队列,并挂起,等待状态可用时被唤醒,具体的请参考AQS的实现,在这里我们需要知道:
(1)AQS里维护了一个状态state,int型,通过状态可以达到线程的访问控制,AQS提供了getState(),setState(),compareAndSet()方法来操作次状态;
(2)AQS维护了一个同步队列,如果当前线程获取不到状态,则进入同步队列中等待;
对于ReentrantLock,这个状态就代表锁,由于是可重入的,state的值就代表线程持有锁的次数。所以,真正对我们重要的是tryAcquire和tryRelease的行为。此时,我们有两种方式来继续我们分析,一种是按内部类来分析,先分析Sync,在分析它的两个子类;一种是按功能来分析,先分析加锁的实现,在分析解锁的实现。由于ReentrantLock是重点,所以我还是倾向于从实现锁的角度来分析。
获取锁
ReentrantLock获取锁的代码如下:
/** * 获得锁,如果锁没有被占用,获得锁,计数为1,立即返回; * 如果锁是有当前线程占用,计数加1,返回; * 如果锁被其他线程占用,阻塞; */ public void lock() { sync.lock(); }可以看到它果然是把实现代理给了同步器,在前面关于ReentrantLock的结构中,我们已经知道了,sync要么是FairSync的实例,要么是NonfairSync的实例。那我们就分别看看公平锁和非公平锁的实现。
公平策略的锁获取
/** AQS acquire(1) */ final void lock() { acquire(1); } /** * 公平的tryAcquire(),成功获得锁,返回true,不成功,返回false,不会阻塞; * 由于是公平的,所以在锁可用时,需要判断当前线程是否是等待时间最长的 */ protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); //c==0说明没有线程获得锁,这里是公平锁的实现,还有判断是否有线程比当前线程等待的时间长 //如果当前线程就是等待时间最长的,使用CAS修改状态,成功则说明获得锁,返回true 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; }前面已经说了,acquire是一个模板方法,它负责完成状态的获取,根据子类的tryAcquire来实现不同的目的,所以重点是tryAcquire。公平的意思是,当出现多线程争用时,锁倾向于将访问权授予等待时间最长的线程。上面tryAcquire包含的逻辑是:
(1)首先获得当前线程和锁的状态
(2)如果锁是可用的,但是还不能直接获取,因为实现的是公平策略,要先看看AQS的同步队列中是否有比自己等待时间还长的线程,如果没有,则使用CAS修改锁的状态,修改成功,则获得锁成功;修改失败,则说明获得锁失败;
(3)如果锁已经被占用,由于是可重入的,所以要判断锁是不是被当前线程锁占用。如果是,则将锁计数加1,返回true,表示获取锁成功;
非公平策略的锁获取
/** * 使用闯入策略来实现非公平的锁,如果闯入失败,则进入正常的获取流程 * 首先就去尝试修改状态,如果修改成功,则获得锁,如果没有成功,就去同步队列排队把 */ final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); } /** * 调用Sync的nonfairTryAcquire(acquires) */ protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); }非公平策略使用闯入来实现锁的获取,如果当前线程需要获得锁,首先就去尝试修改锁的状态,如果修改成功,则获得锁成功,修改失败,则进入同步队列中等待。公平策略和非公平策略的却别就是是否使用闯入,如果是非公平策略,线程二话不说,上来就尝试获取锁,而公平策略则是直接进入同步队列中去。在上面的代码中,tryAcquire又由nonfairTryAcquire来实现,这个方法是Sync实现的,不明白Doug Lea为什么要把非公平策略的实现放到父类。还是来看看nonfairTryAcquire方法吧:
/** * 非公平的tryLock,tryAcquire的行为由子类实现,线程不会被阻塞。首先判断状态 * 1.如果状态是0,说明锁可用,则使用CAS修改状态,如果成功,由当前线程获得,则返回true * 2.如果锁已经被占用,判断锁的拥有者是不是当前线程,如果是,设置状态,返回true,注意溢出 * 3.如果锁已经被其他线程占用,获取失败,返回false */ final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); //如果锁可用,设置state的状态,返回 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; }和公平策略的tryAcquire差不多,所不同的就是当锁可用时,公平策略需要判断是否有等待时间更长的线程,而非公平策略则直接尝试修改以获得锁。
释放锁
使用unlock释放锁,公平和非公平在释放锁的行为是一样的。ReentrantLock的unlock方法:
/** * 尝试去释放锁,调用AQS的release(1),AQS.release(1)的行为: * 首先调用tryRelease(1),由于Sync重写了tryRelease;如果返回true表示锁可用 * 然后,去唤醒后继节点。 */ public void unlock() { sync.release(1); }还是调用AQS的release方法,AQS的release去调用具体的tryRelease方法。tryRelease由Sync来实现,其代码如下:
/** * 尝试释放锁,设置锁的计数。经过释放后如果锁可用返回true,否则返回false */ protected final boolean tryRelease(int releases) { int c = getState() - releases; //如果锁不是由当前线程持有,出错了,抛异常 if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; //c==0说明没有线程占用锁 if (c == 0) { free = true; setExclusiveOwnerThread(null); } setState(c); return free; }其包含的逻辑:
(1)首先获得锁被持有的次数,减去1,在ReentrantLock中acquire和release中的所有参数都被写死为1,因为一次lock代表获取锁一次,unlock代表解锁1次;
(2)如果锁不是由当前线程持有的,抛异常;
(3)判断锁是否被持有,如果锁已经空闲,则返回true,如果锁仍然被占有,返回false。
到这里就把ReentrantLock最基本的实现原理讲明白了,可以看到最关键的实现还是由AQS来完成的。ReentrantLock还包含了tryLock()方法,tryLock是通过Sync的nonfairTryAcquire来实现的,如果锁可用则尝试获取,不论成功或者失败,都立即返回。还有可中断和超时的tryLock,具体用法参考API,其实现都是由AQS来实现的。
附录源码
/** * 一个可重入的互斥锁,与内置的synchronized具有相同的语义,但是功能更强大 */ public class ReentrantLock implements Lock, java.io.Serializable { private static final long serialVersionUID = 7373984872572414699L; /** 所有的实现都有sync来实现 */ private final Sync sync; /** * 基本的同步器实现,继承自AQS,子类通过继承它来实现公平的和非公平的策略, * 使用AQS的state字段代表持有锁的次数 */ abstract static class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = -5179523762034025860L; /** * Lock.lock方法的实现,是一个抽象方法 */ abstract void lock(); /** * 非公平的tryLock,tryAcquire的行为由子类实现,线程不会被阻塞。首先判断状态 * 1.如果状态是0,说明锁可用,则使用CAS修改状态,如果成功,由当前线程获得,则返回true * 2.如果锁已经被占用,判断锁的拥有者是不是当前线程,如果是,设置状态,返回true,注意溢出 * 3.如果锁已经被其他线程占用,获取失败,返回false */ final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); //如果锁可用,设置state的状态,返回 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; } /** * 尝试释放锁,设置锁的计数。经过释放后如果锁可用返回true,否则返回false */ protected final boolean tryRelease(int releases) { int c = getState() - releases; //如果锁不是由当前线程持有,出错了,抛异常 if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; //c==0说明没有线程占用锁 if (c == 0) { free = true; setExclusiveOwnerThread(null); } setState(c); return free; } /** 返回锁是否由当前线程持有 */ protected final boolean isHeldExclusively() { return getExclusiveOwnerThread() == Thread.currentThread(); } final ConditionObject newCondition() { return new ConditionObject(); } //依赖于外部类的方法 final Thread getOwner() { return getState() == 0 ? null : getExclusiveOwnerThread(); } final int getHoldCount() { return isHeldExclusively() ? getState() : 0; } final boolean isLocked() { return getState() != 0; } /** 序列化 */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); setState(0); // reset to unlocked state } } /**Sync子类包括两个方法void lock(),会阻塞;tryAcquire()不会阻塞*/ /** * 非公平锁的实现 */ static final class NonfairSync extends Sync { private static final long serialVersionUID = 7316153563782823691L; /** * 使用闯入策略来实现非公平的锁,如果闯入失败,则进入正常的获取流程 * 首先就去尝试修改状态,如果修改成功,则获得锁,如果没有成功,就去同步队列排队把 */ final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); } /** * 调用Sync的nonfairTryAcquire(acquires) */ protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); } } /** * 公平锁 */ static final class FairSync extends Sync { private static final long serialVersionUID = -3000897897090466540L; /** AQS acquire(1) */ final void lock() { acquire(1); } /** * 公平的tryAcquire(),成功获得锁,返回true,不成功,返回false,不会阻塞; * 由于是公平的,所以在锁可用时,需要判断当前线程是否是等待时间最长的 */ protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); //c==0说明没有线程获得锁,这里是公平锁的实现,还有判断是否有线程比当前线程等待的时间长 //如果当前线程就是等待时间最长的,使用CAS修改状态,成功则说明获得锁,返回true 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; } } /** * 无参构造方法,使用非公平策略 */ public ReentrantLock() { sync = new NonfairSync(); } /**true 公平策略;false 非公平策略 */ public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); } /** * 获得锁,如果锁没有被占用,获得锁,计数为1,立即返回; * 如果锁是有当前线程占用,计数加1,返回; * 如果锁被其他线程占用,阻塞; */ public void lock() { sync.lock(); } /** * 可中断的锁获取,通过AQS acquireInterruptibly(1)来实现。 * 获得锁,如果锁没有被占用,获得锁,计数为1,立即返回; * 如果锁是有当前线程占用,增加计数1,返回; * 如果锁被其他线程占用,阻塞当前线程,在西面两个条件发生之前,一直休眠: * (1)锁有当前线程获得; * (2)当前线程被中断; * 如果锁被当前线程获得,则计数为1。 * 如果当前线程在进入方法时中断状态被设置或者在等待锁期间被其他线程阻塞, * 则抛出InterruptionException,并清楚当前线程的中断状态。 * 这是一个显式中断点,应该悠闲考虑响应。 */ public void lockInterruptibly() throws InterruptedException { sync.acquireInterruptibly(1); } /** 调用Sync的nonfairTryAcquire(1) */ public boolean tryLock() { return sync.nonfairTryAcquire(1); } /** 可中断的超时获取锁,超时或者中断都会终止 */ public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireNanos(1, unit.toNanos(timeout)); } /** * 尝试去释放锁,调用AQS的release(1),AQS.release(1)的行为: * 首先调用tryRelease(1),由于Sync重写了tryRelease;如果返回true表示锁可用 * 然后,去唤醒后继节点。 */ public void unlock() { sync.release(1); } /** * Returns a {@link Condition} instance for use with this * {@link Lock} instance. * * <p>The returned {@link Condition} instance supports the same * usages as do the {@link Object} monitor methods ({@link * Object#wait() wait}, {@link Object#notify notify}, and {@link * Object#notifyAll notifyAll}) when used with the built-in * monitor lock. * * <ul> * * <li>If this lock is not held when any of the {@link Condition} * {@linkplain Condition#await() waiting} or {@linkplain * Condition#signal signalling} methods are called, then an {@link * IllegalMonitorStateException} is thrown. * * <li>When the condition {@linkplain Condition#await() waiting} * methods are called the lock is released and, before they * return, the lock is reacquired and the lock hold count restored * to what it was when the method was called. * * <li>If a thread is {@linkplain Thread#interrupt interrupted} * while waiting then the wait will terminate, an {@link * InterruptedException} will be thrown, and the thread's * interrupted status will be cleared. * * <li> Waiting threads are signalled in FIFO order. * * <li>The ordering of lock reacquisition for threads returning * from waiting methods is the same as for threads initially * acquiring the lock, which is in the default case not specified, * but for <em>fair</em> locks favors those threads that have been * waiting the longest. * * </ul> * * @return the Condition object */ public Condition newCondition() { return sync.newCondition(); } /** * 查询当前线程持有锁的次数(可重入),持有次数是典型的仅仅用来测试和调试的方法 * @return 0 如果当前线程不持有锁;num,持有的次数。 */ public int getHoldCount() { return sync.getHoldCount(); } /** 判断锁是否被当前线程持有。*/ public boolean isHeldByCurrentThread() { return sync.isHeldExclusively(); } /** * 查询锁是否被占用,此方法用于监视系统状态,不用于同步 */ public boolean isLocked() { return sync.isLocked(); } /** * 判断是否是公平锁 * @return 如果构造的是FairSync的实例,则返回ture */ public final boolean isFair() { return sync instanceof FairSync; } /** * 返回持有锁的线程,如果锁是可用状态则返回null。此方法实际是由 * AbstractOwnableSynchronizer.getExclusiveOwnerThread()实现 * AbstractOwnableSynchronizer里使用exclusiveOwnerThread保存当前 * 拥有状态的线程。 */ protected Thread getOwner() { return sync.getOwner(); } /** * 检查是否有线程在同步队列中等待获取锁,有AQS hasQueuedThread()实现 * 注意:注意,因为随时可能发生取消,所以返回 true 并不保证有其他线程ever acquire此锁。 * 此方法主要用于监视系统状态。 */ public final boolean hasQueuedThreads() { return sync.hasQueuedThreads(); } /** * 查询给定线程是否正在等待获取此锁。 * 注意,因为随时可能发生取消,所以返回true并不保证此线程ever acquire。 * 此方法主要用于监视系统状态 */ public final boolean hasQueuedThread(Thread thread) { return sync.isQueued(thread); } /** * 返回正等待获取此锁的线程估计数。 * 该值仅是估计的数字,因为在此方法遍历内部数据结构的同时,线程的数目可能动态地变化。 * 此方法用于监视系统状态,不用于同步控制。 */ public final int getQueueLength() { return sync.getQueueLength(); } /** * 返回一个 collection,它包含可能正等待获取此锁的线程。 * 因为在构造此结果的同时实际的线程 set 可能动态地变化,所以返回的 collection 仅是尽力的估计值。 * 所返回 collection 中的元素没有特定的顺序。此方法用于加快子类的构造速度,以提供更多的监视设施。 */ protected Collection<Thread> getQueuedThreads() { return sync.getQueuedThreads(); } }转载请注明:喻红叶《Java并发-ReentrantLock源码分析》
相关推荐
ReentrantLock类的源码分析对理解Java并发机制非常重要。本文将对ReentrantLock类的源码进行详细分析,涵盖ReentrantLock的继承关系、构造方法、锁机制、加锁和解锁机制等方面。 ReentrantLock的继承关系 ...
在深入ReentrantLock之前,我们首先需要了解Java并发编程的基础,特别是Java内存模型和线程同步机制。 **可重入锁与可重入性** 可重入锁允许同一个线程反复进入它已经拥有的锁所保护的代码段。在Java中,...
Java并发系列之ReentrantLock源码分析 ReentrantLock是Java 5.0中引入的一种新的加锁机制,它实现了Lock接口,并提供了与synchronized相同的互斥性和内存可见性。ReentrantLock的底层实现是通过AQS来实现多线程同步...
### 三、ReentrantLock源码分析 #### 3.1 ReentrantLock介绍 ReentrantLock是一种基于AQS框架实现的可重入锁。它可以显式地控制锁的获取和释放,并提供了公平性和非公平性两种获取策略。此外,ReentrantLock还支持...
09-深入理解AQS之独占锁ReentrantLock源码分析-fox 10-深入理解AQS之Semaphorer&CountDownLatch&CyclicBarrie详解-fox 11-深入理解AQS之CyclicBarrier&ReentrantReadWriteLock详解-fox 12-深入理解AQS之...
9. **源码分析**:jcip-examples-src.jar包含了书中示例的源代码,读者可以通过阅读和运行这些例子来加深对并发编程的理解。 通过学习《Java并发编程实践》,开发者将能够更好地理解和利用Java平台的并发特性,编写...
线程池、锁机制(如synchronized关键字,ReentrantLock等)和并发容器(如ConcurrentHashMap)可以帮助优化并发性能,保证系统的稳定运行。 六、用户认证与权限管理 为了保证系统的安全,通常需要实现用户注册、...
"java并发源码分析之实战编程"这个主题深入探讨了Java平台上的并发处理机制,旨在帮助开发者理解并有效地利用这些机制来提高程序性能和可扩展性。在这个专题中,我们将围绕Java并发库、线程管理、锁机制、并发容器...
《Java并发编程的艺术》这本书是Java开发者深入理解并发编程的重要参考书籍。这本书全面地介绍了Java平台上的并发和多线程编程技术,旨在帮助开发者解决在实际工作中遇到的并发问题,提高程序的性能和可伸缩性。 ...
源码分析: 1. **线程与多线程**:Java中的线程是并发编程的基础,通过`Thread`类或实现`Runnable`接口可以创建线程。源码中可能包含各种线程的创建和管理方式,如`start()`方法启动线程,`join()`等待线程结束,...
通过分析和学习这些源码,我们可以更深入地理解Java并发库的实际运用,并提升我们的并发编程技能。 总的来说,Java并发库是构建高性能、高并发应用的核心,熟练掌握其原理和实践,对于任何Java开发者来说都是不可或...
在这个压缩包中,包含了源码和PDF版的书籍内容,是学习和研究Java并发编程的重要资源。 并发编程是现代计算机系统中不可或缺的一部分,特别是在Java这种广泛用于企业级应用的平台上。Java提供了强大的并发工具和API...
通过对《Java并发编程艺术》源码的深入学习,你可以掌握上述知识点,并能够运用到实际项目中,编写出更加稳定和高效的并发程序。书中的例子和源码将有助于你理解和实践这些理论,从而提升你的并发编程能力。
Java多线程并发实战与源码分析是Java开发中至关重要的一部分,它涉及到程序性能优化、系统资源高效利用以及复杂逻辑的正确同步。本书主要聚焦于Java多线程的基础理论和实际应用,虽然书中实例和源码相对较少,但仍然...
6. **源码分析**:jcip-examples-src.rar中包含的源码实例是对书中理论知识的实践展示,读者可以下载并运行这些代码,以加深对并发编程的理解和应用。 7. **版本差异**:压缩包中提供了有目录和无目录、彩色版本的...
本资源提供了"java并发编程源码",包括jcip-examples-src.jar、jcip-annotations-src.jar和jcip-annotations.jar三个文件。这些源码可以帮助开发者深入理解Java并发编程的原理和实践,同时也可直接引入到工程中使用...
在Java并发编程中,`AbstractQueuedSynchronizer`(AQS)是一个重要的抽象类,用于构建锁和其他同步组件。AQS的核心是通过一个整型变量`state`来表示同步状态,并利用双端队列(FIFO)管理等待的线程。在本篇中,我们...
总的来说,《Java并发编程实战》这本书不仅提供了丰富的理论知识,还通过大量的实例源码帮助读者将理论付诸实践,是Java开发者提升并发编程技能的必备参考。通过学习书中的内容,开发者能够更好地理解和掌握Java并发...
Java并发编程是Java开发中的重要领域,特别是在多核处理器和分布式系统中,高效地利用并发可以极大地提升程序的性能和响应速度。`Java-concurrency-master.zip`这个压缩包很可能包含了关于Java并发编程的各种资料和...
Java并发容器CopyOnWriteArrayList实现原理及源码分析 Java并发容器CopyOnWriteArrayList是Java并发包中提供的一个并发容器,实现了线程安全且读操作无锁的ArrayList,写操作则通过创建底层数组的新副本来实现。...