AQS---ReentrantLock
概述
A reentrant mutual exclusion {@link Lock} with the same basic behavior and semantics as the implicit monitor lock accessed using {@code synchronized} methods and statements, but with extended capabilities.
一个可重入的互斥Lock,和synchronized有相同的基本语义和行为,但有扩展能力;
A {@code ReentrantLock} is <em>owned</em> by the thread last successfully locking, but not yet unlocking it.
ReentrantLock是线程自有的;
A thread invoking {@code lock} will return, successfully acquiring the lock, when the lock is not owned by another thread.
当锁不被其他线程占用,一个线程调用Lock将会成功获得lock;
The method will return immediately if the current thread already owns the lock.
如果当前线程已拥有Lock,将会立即return;
This can be checked using methods {@link #isHeldByCurrentThread}, and {@link #getHoldCount}.
可以使用isHeldByCurrentThread(), getHoldCount() 检测Lock占用情况;
The constructor for this class accepts an optional <em>fairness</em> parameter.
构造器支持一个fairness参数;
When set {@code true}, under contention, locks favor granting access to the longest-waiting thread.
当构造器参数为true,为公平锁,优先等待时间最长的线程;
Programs using fair locks accessed by many threads may display lower overall throughput (i.e., are slower; often much slower) than those using the default setting, but have smaller variances in times to obtain locks and guarantee lack of starvation.
使用 公平锁 比 非公平锁 可能有较低的吞吐量,但在获得lock和保证无饥饿 差异较小;
Note however, that fairness of locks does not guarantee fairness of thread scheduling.
公平锁 不能保证线程调度的公平性;
Thus, one of many threads using a fair lock may obtain it multiple times in succession while other active threads are not progressing and not currently holding the lock.
公平锁 可能导致 一个线程多次获得lock,而 其他线程获得不了lock;
Also note that the untimed {@link #tryLock()} method does not honor the fairness setting.
注意:tryLock()无时间参数的 不遵守公平设置;
It is recommended practice to <em>always</em> immediately follow a call to {@code lock} with a {@code try} block, most typically in a before/after construction such as:
推荐 在调用lock() 后 跟随一个 try...finally...块:
reentrantLock.lock();
try {
// method body
}finally{
reentrantLock.unlock();
}
In addition to implementing the {@link Lock} interface, this class defines a number of {@code public} and {@code protected} methods for inspecting the state of the lock.
除了实现lock接口外,该类定义了大量的public、protected方法检测锁的状态;
Some of these methods are only useful for instrumentation and monitoring.
对监控有用;
Serialization of this class behaves in the same way as built-in locks: a deserialized lock is in the unlocked state, regardless of its state when serialized.
该类的序列化行为 和 内置锁一样,反序列化将忽略状态(反序列化lock是unlock状态);
This lock supports a maximum of 2147483647 recursive locks by the same thread. Attempts to exceed this limit result in {@link Error} throws from locking methods.
一个线程最大支持2147483647递归lock,超限制将会报error异常;
链路
lock()
// java.util.concurrent.locks.ReentrantLock.lock public void lock() { sync.lock(); } // java.util.concurrent.locks.ReentrantLock.FairSync.lock 【公平获取锁】 final void lock() { acquire(1); } // java.util.concurrent.locks.ReentrantLock.NonfairSync.lock 【非公平获取锁】 final void lock() { // 如果直接获取锁成功 -> 设置当前线程独占 if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); // 如果获取锁失败 -> 再次尝试获取锁 & 如果获取失败 -> 以独占模式加入队列 else acquire(1); } // java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire /** * Acquires in exclusive mode */ public final void acquire(int arg) { // 如果获取锁失败 && 以独占模式加入队列成功 -> 将当前线程中断 if (!tryAcquire(arg) && acquireQueued(addWaiter(AbstractQueuedSynchronizer.Node.EXCLUSIVE), arg)) selfInterrupt(); } // java.util.concurrent.locks.ReentrantLock.FairSync.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; }
unlock()
// java.util.concurrent.locks.ReentrantLock.unlock public void unlock() { sync.release(1); } // java.util.concurrent.locks.AbstractQueuedSynchronizer.release /** * Releases in exclusive mode. */ public final boolean release(int arg) { // 如果 以独占模式释放锁 成功 && 有等待的线程 -> 唤醒等待的线程 if (tryRelease(arg)) { AbstractQueuedSynchronizer.Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h); return true; } return false; } // java.util.concurrent.locks.ReentrantLock.Sync.tryRelease protected final boolean tryRelease(int releases) { int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; // 如果c=0 -> 锁释放成功 && 独占线程置为null if (c == 0) { free = true; setExclusiveOwnerThread(null); } setState(c); return free; }
使用场景
互斥锁
static ReentrantLock reentrantLock = new ReentrantLock(true); public static void main(String[] args) { Task task = new Task(); Thread t1 = new Thread(task); Thread t2 = new Thread(task); Thread t3 = new Thread(task); t1.start(); t2.start(); t3.start(); } static class Task implements Runnable{ @Override public void run() { try { reentrantLock.lock(); System.out.println(Thread.currentThread().getName() + "获得lock"); } finally { reentrantLock.unlock(); System.out.println(Thread.currentThread().getName() + "释放lock"); } } } 结果: Thread-0获得lock Thread-0释放lock Thread-1获得lock Thread-1释放lock Thread-2获得lock Thread-2释放lock
lock、tryLock
区别
Lock:
如果锁当前未被其他线程持有,则立即获取锁;
如果锁已经被其他线程持有,则当前线程会进入阻塞状态,直到锁变得可用为止。一旦线程获得了锁,它就会保持锁直到显式调用 unlock()
方法释放锁。
如果锁不可用,线程会一直等待,直到锁可用。
场景:
用于确保线程能够在获取锁后执行关键操作,适合于需要长期等待锁的场景;
tryLock:
试图获取锁,但它不会阻塞等待。如果锁当前未被其他线程持有,则立即获取锁;
如果锁已经被其他线程持有,则当前线程不会等待,而是立即返回 false
。
场景:
用于尝试获取锁而不阻塞等待,适合于不需要长时间等待锁的场景,或者当锁不可用时可以采取其他行动的场景;
lock.tryLock()
即使此锁已设置为使用公平排序策略,对tryLock的调用也会立即获取可用的锁,无论其他线程当前是否正在等待该锁。
这种讨价还价行为在某些情况下可能是有用的,即使它破坏了公平。
如果你想遵守此锁的公平性设置,那么使用{@link#tryLock(long,TimeUnit)tryLock(0,TimeUnit.SECONDS)},这几乎是等效的(它也能检测到中断)。
如果当前线程已经持有此锁,则持有计数将增加1,该方法将返回{@code true}。
如果锁由另一个线程持有,则此方法将立即返回值{@code false}。
非公平锁
/** * ReentrantLock lock = new ReentrantLock(); * lock.tryLock(); * * java.util.concurrent.locks.ReentrantLock#tryLock() * public boolean tryLock() { * return sync.nonfairTryAcquire(1); * } * * java.util.concurrent.locks.ReentrantLock.Sync#nonfairTryAcquire(int) * 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()) { // 如果 有线程持有锁 & 独占线程是自己 -> 重复获取锁 state+1 * int nextc = c + acquires; * if (nextc < 0) // overflow * throw new Error("Maximum lock count exceeded"); * setState(nextc); * return true; * } * return false; * } */
公平锁
/** * ReentrantLock lock = new ReentrantLock(true); * lock.tryLock(); * * java.util.concurrent.locks.ReentrantLock#tryLock() // 和非公平锁逻辑一样,以独占式获取锁 * public boolean tryLock() { * return sync.nonfairTryAcquire(1); * } * * java.util.concurrent.locks.ReentrantLock.Sync#nonfairTryAcquire(int) * 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()) { // 如果 有线程持有锁 & 独占线程是自己 -> 重复获取锁 state+1 * int nextc = c + acquires; * if (nextc < 0) // overflow * throw new Error("Maximum lock count exceeded"); * setState(nextc); * return true; * } * return false; * } */
lock.lock()
获得锁。
如果锁未被其他线程持有,则获取锁并立即返回,将锁持有计数设置为1。
如果当前线程已经持有锁,则持有计数将增加1,方法将立即返回。
如果锁由另一个线程持有,则当前线程出于线程调度目的而被禁用,并处于休眠状态,直到获取到锁为止,此时锁持有计数设置为1。
非公平锁
/** * ReentrantLock lock = new ReentrantLock(); * lock.lock() * * java.util.concurrent.locks.ReentrantLock#lock() * public void lock() { * sync.lock(); * } * * java.util.concurrent.locks.ReentrantLock.Sync#lock() * abstract void lock(); * * java.util.concurrent.locks.ReentrantLock.NonfairSync#lock() * final void lock() { * if (compareAndSetState(0, 1)) // 如果获取锁成功 -> 设置当前线程独占 * setExclusiveOwnerThread(Thread.currentThread()); * else // 否则 -> 独占式获取锁 * acquire(1); * } * * java.util.concurrent.locks.AbstractQueuedSynchronizer#acquire(int) * public final void acquire(int arg) { * if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) // 如果获取锁失败 & 加入同步队列成功 -> 自我中断阻塞 * selfInterrupt(); * } * * java.util.concurrent.locks.AbstractQueuedSynchronizer#tryAcquire(int) * protected boolean tryAcquire(int arg) { * throw new UnsupportedOperationException(); * } * * java.util.concurrent.locks.ReentrantLock.NonfairSync#tryAcquire(int) * protected final boolean tryAcquire(int acquires) { * return nonfairTryAcquire(acquires); * } * * java.util.concurrent.locks.ReentrantLock.Sync#nonfairTryAcquire(int) // 和tryLock一样的逻辑 * 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()) { // 如果 有线程持有锁 & 独占线程是自己 -> 重复获取锁 state+1 * int nextc = c + acquires; * if (nextc < 0) // overflow * throw new Error("Maximum lock count exceeded"); * setState(nextc); * return true; * } * return false; * } * * java.util.concurrent.locks.AbstractQueuedSynchronizer#acquireQueued(java.util.concurrent.locks.AbstractQueuedSynchronizer.Node, int) * final boolean acquireQueued(final Node node, int arg) { * boolean failed = true; * try { * boolean interrupted = false; * for (;;) { * final Node p = node.predecessor(); * if (p == head && tryAcquire(arg)) { * setHead(node); * p.next = null; // help GC * failed = false; * return interrupted; * } * if (shouldParkAfterFailedAcquire(p, node) && * parkAndCheckInterrupt()) * interrupted = true; * } * } finally { * if (failed) * cancelAcquire(node); * } * } * */
公平锁
/** * ReentrantLock lock = new ReentrantLock(true); * lock.lock(); * * java.util.concurrent.locks.ReentrantLock#lock() * public void lock() { * sync.lock(); * } * * java.util.concurrent.locks.ReentrantLock.Sync#lock() * abstract void lock(); * * java.util.concurrent.locks.ReentrantLock.FairSync#lock() * final void lock() { * acquire(1); * } * * java.util.concurrent.locks.AbstractQueuedSynchronizer#acquire(int) // 和非公平锁逻辑一样 * public final void acquire(int arg) { * if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) // 如果获取锁失败 & 加入同步队列成功 -> 自我中断阻塞 * selfInterrupt(); * } * * java.util.concurrent.locks.AbstractQueuedSynchronizer#tryAcquire(int) * protected boolean tryAcquire(int arg) { * throw new UnsupportedOperationException(); * } * * java.util.concurrent.locks.ReentrantLock.NonfairSync#tryAcquire(int) * protected final boolean tryAcquire(int acquires) { * return nonfairTryAcquire(acquires); * } * * java.util.concurrent.locks.ReentrantLock.Sync#nonfairTryAcquire(int) // 和tryLock一样的逻辑 * 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()) { // 如果 有线程持有锁 & 独占线程是自己 -> 重复获取锁 state+1 * int nextc = c + acquires; * if (nextc < 0) // overflow * throw new Error("Maximum lock count exceeded"); * setState(nextc); * return true; * } * return false; * } * * java.util.concurrent.locks.AbstractQueuedSynchronizer#acquireQueued(java.util.concurrent.locks.AbstractQueuedSynchronizer.Node, int) * final boolean acquireQueued(final Node node, int arg) { * boolean failed = true; * try { * boolean interrupted = false; * for (;;) { * final Node p = node.predecessor(); * if (p == head && tryAcquire(arg)) { * setHead(node); * p.next = null; // help GC * failed = false; * return interrupted; * } * if (shouldParkAfterFailedAcquire(p, node) && * parkAndCheckInterrupt()) * interrupted = true; * } * } finally { * if (failed) * cancelAcquire(node); * } * } */
公平锁与非公平锁的区别
/** * java.util.concurrent.locks.ReentrantLock.FairSync#lock() * final void lock() { * acquire(1); * } * * java.util.concurrent.locks.ReentrantLock.NonfairSync#lock() * final void lock() { * if (compareAndSetState(0, 1)) 非公平锁 无视同步队列,直接去获取锁 * setExclusiveOwnerThread(Thread.currentThread()); * else * acquire(1); * } */