state 为0,表示锁未被获取
不为0,表示已被获取
compareAndSetState(0, acquires)
获取锁时,设置state为acquires
setExclusiveOwnerThread(current)
获取锁时,设置线程为当前线程
可重入:
已获取到锁时,再次进入时state 加上acquires即可
public class ReentrantLock implements Lock, java.io.Serializable { private final Sync sync; public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); } public void lock() { sync.lock(); } public void unlock() { sync.release(1); // 这个1表示退出锁1次。 } // 带超时限制的获取 public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireNanos(1, unit.toNanos(timeout)); } // 其他代码省略 }
可以看到,ReentrantLock都是把具体实现委托给内部类而不是直接继承自AbstractQueuedSynchronizer,这样的好处是用户不会看到不需要的方法,也避免了用户错误地使用AbstractQueuedSynchronizer的公开方法而导致错误。
ReentrantLock的重入计数是使用AbstractQueuedSynchronizer的state属性的,state大于0表示锁被占用、等于0表示空闲,小于0则是重入次数太多导致溢出了。
ReentrantLock.Sync
可重入锁内部实现的超类,主要实现了公平与非公平锁的共有方法,并提供了加锁操作的统一抽象:abstract void lock();,还有核心的释放锁的操作。
abstract static class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = -5179523762034025860L; // 执行Lock.lock()方法,留给子类根据其公平性实现。 // 子类化的最主要原因是允许非公平的快速路径。 abstract void lock(); // 非公平获取 final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { // 锁是空闲的,进行加锁必须用CAS来确保即使有多个线程竞争锁也是安全的 if (compareAndSetState(0, acquires)) { // 加锁成功 // 把当前线程设为锁的持有者,在获取前可用于判断是否是重入。 setExclusiveOwnerThread(current); return true ; } } else if (current == getExclusiveOwnerThread()) { // 锁被占用且当前线程是锁的持有者,说明是重入。 int nextc = c + acquires; if (nextc < 0) // 溢出。加锁次数从0开始,加锁与释放操作是对称的, // 所以绝不会是小于0值,小于0只能是溢出。 throw new Error("Maximum lock count exceeded"); // 锁被持有的情况下,只有持有者才能更新锁保护的资源, // 所以这里不需要用CAS。 setState(nextc); return true ; } return false ; } protected final boolean tryRelease(int releases) { // 先读取state是为了获得一个读屏障,owner不是volatile的。 int c = getState() - releases; // 只有锁的持有者才能释放锁 if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) {// 锁重入计数减到0,需要真正释放锁了。 free = true; setExclusiveOwnerThread( null); } // 如果c为0,写操作完成后,其他线程就会看到锁被释放了, // 所以setExclusiveOwnerThread必须在这个写之前完成。 setState(c); return free; } 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(); } final ConditionObject newCondition() { return new ConditionObject(); } // Methods relayed from outer class final Thread getOwner() { return getState() == 0 ? null : getExclusiveOwnerThread(); } final int getHoldCount() { return isHeldExclusively() ? getState() : 0; // 以state属性作为加锁次数。 } final boolean isLocked() { return getState() != 0; // 加锁次数为0表示没有被拥有 } private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); setState(0); // reset to unlocked state } }
ReentrantLock.FairSync
提供公平性的锁实现。实现公平性的关键在于:如果锁被占用且当前线程不是持有者也不是等待队列的第一个,则进入等待队列。
static final class FairSync extends Sync { private static final long serialVersionUID = -3000897897090466540L; final void lock() { acquire(1); //acquire会首先调用tryAcquire,所以公平策略的控制留给tryAcquire。 } // tryAcquire的公平版本。除非是递归调用或没有等待者或者是第一个,否则不授予访问。 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 ; } }
ReentrantLock.NonfairSync
static final class NonfairSync extends Sync { private static final long serialVersionUID = 7316153563782823691L; // 执行lock。尝试立即闯入,失败就退回常规流程 final void lock() { if (compareAndSetState(0, 1))// 首先进行获取 // 获取成功,把当前线程设为持有者 setExclusiveOwnerThread(Thread.currentThread()); else // 获取失败,进入常规流程:acquire会首先调用tryAcquire, acquire(1); } protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); } }
获取锁:
//NonfairSync final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); } //FairSync final void lock() { acquire(1); }
public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }
1)在资源没有被占用的情况下:
非公平锁是:
先state+1,然后直接得到锁,
而公平锁则是:
先尝试去获取锁,如果得到了锁则state+1.
2)如果是同一线程,再次申请锁.
两种锁,表现基本一致,可以参考下面的代码块.
else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); return true; }
。
相关推荐
ReentrantLock的实现主要依赖于3个内部类:Sync、FairSync和NonfairSync。它们都继承自AbstractQueuedSynchronizer(AQS),AQS是Java并发包中一个重要的抽象类,用于构建锁和其他同步组件的基础框架。 Sync是...
ReentrantLock类内部定义了两个实现类:NonfairSync和FairSync。NonfairSync是非公平锁,FairSync是公平锁。 ReentrantLock的构造方法 ReentrantLock类有两个构造方法: 1. ReentrantLock() 2. ReentrantLock...
1. **`ReentrantLock`的`tryAcquire`实现**:在`ReentrantLock`中,`tryAcquire`方法的具体实现在`NonFairSync`和`FairSync`中有所不同。对于`NonFairSync`,它会尝试直接使用CAS操作来修改`state`值,如果成功,则...
acquireSharedInterruptibly方法首先就是去调用tryAcquireShared方法去尝试获取,tryAcquireShared在AQS里面是抽象方法,FairSync和NonfairSync这两个派生类实现了该方法的逻辑。FairSync实现的是公平获取的逻辑,而...
ReentrantLock的内部类Sync继承自AQS,进一步分为FairSync(公平锁)和NonfairSync(非公平锁)两个子类。公平锁确保线程按照它们请求锁的顺序获取锁,而非公平锁则不保证这种顺序,可能会有线程插队获取锁。 **...
`Sync`是一个抽象类,它是`ReentrantLock`的核心实现,分为公平锁`FairSync`和非公平锁`NonFairSync`两个子类。默认情况下,`ReentrantLock`使用的是非公平锁,因为非公平锁在大多数情况下具有更高的吞吐量。 `Sync...
在构造函数中,`sync = new NonfairSync()` 或 `sync = new FairSync()` 分别用于创建非公平锁和公平锁,这里的`sync`是一个内部类,它是`AbstractQueuedSynchronizer`(AQS)的子类。 3. **内部类结构** - `Sync...
3. `FairSync` 和 `NonFairSync`:`FairSync` 是一种公平锁,它继承自 `Sync`,并重写了 `tryAcquire(arg)` 方法以实现公平锁逻辑。`NonFairSync` 是一种非公平锁,它也继承自 `Sync`,但不保证公平性。 4. `Sync`...
- **实现**:ReentrantLock通过AQS封装了静态内部类Sync,进一步细分为公平锁FairSync和非公平锁NonfairSync。在尝试获取锁时,公平锁遵循FIFO原则,而非公平锁则可能跳过等待队列中的线程。 3. **...
Semaphore类有两个内部静态类——NonfairSync和FairSync,分别对应非公平锁和公平锁。在构造Semaphore时,可以通过传入布尔值决定使用哪种类型的锁。 在Semaphore中,`acquire()`方法用于获取一个许可,如果当前...
在ReentrantLock内部,公平锁(FairSync)和非公平锁(NonfairSync)都是对Sync的子类实现,分别实现了公平和非公平的锁获取策略。FairSync在尝试获取锁时会检查当前是否有其他线程在等待,而NonfairSync则不会,这...
ReentrantLock的内部实现分为两个子类:`FairSync`(公平锁)和`NonfairSync`(非公平锁)。这两个子类均继承自`Sync`抽象类。 - **FairSync**:按照请求顺序来分配锁,确保了锁获取的公平性,但可能会影响性能。 -...
公平锁(FairSync)和非公平锁(NonfairSync)的实现是通过AQS的扩展来实现的。文章进一步阐释了AQS的多项特性,包括阻塞等待队列、共享/独占模式、公平/非公平锁定、可重入性,以及允许中断的能力。AQS作为基础框架...
以ReentrantLock为例,它有两个内部类,`FairSync`(公平锁)和`NonfairSync`(非公平锁),它们都继承自AQS。`NonfairSync`的`lock()`方法会首先尝试通过CAS直接获取锁,失败后会调用AQS的`acquire()`方法。`...
new FairSync() : new NonfairSync();} 公平锁的处理逻辑 公平锁的处理逻辑与非公平锁基本上是一致的,唯一的不同在于增加了 hasQueuedPredecessors 的逻辑判断,方法名就可知道该方法用来判断当前节点在同步队列...
ReentrantLock的主要结构包括三个内部类:Sync、NonfairSync、FairSync。Sync是一个抽象类,实现了AQS的部分方法;NonfairSync实现了Sync,主要用于非公平锁的获取;FairSync实现了Sync,主要用于公平锁的获取。 ...
sync对象是一个抽象类,有两个具体实现:FairSync(公平锁)和NonfairSync(非公平锁)。它们都继承自AbstractQueuedSynchronizer(AQS),AQS维护了一个volatile状态字段state,用于表示锁的状态,以及一个FIFO等待...
在ReentrantLock的内部,公平锁由FairSync类表示,非公平锁由NonfairSync类表示。在NonfairSync中,lock()方法直接尝试通过compareAndSetState(0, 1)原子地设置锁的状态,如果成功,线程就获得了锁;如果失败,它会...
NonfairSync和FairSync分别代表非公平和公平的锁策略,继承自Sync。 - ReadLock和WriteLock是内部类,实现了Lock接口,分别对应读锁和写锁的接口。 通过理解ReentrantReadWriteLock的工作原理和设计,开发者可以更...
- `NonfairSync`实现了非公平锁逻辑。 #### 7. 理解加锁过程 - **加锁流程**: - 尝试获取锁状态,如果状态为0则尝试CAS设置为1。 - 如果获取失败,将当前线程加入队列,并自旋等待前驱节点释放锁。 - 成功...