ReentrantLock也是一个可重入的互斥锁,跟synchronized提供一样的线程同步功能,但是比synchronized更加灵活,即优化了以上所说的synchronized的不足。
ReentrantLock是基于AQS来实现线程同步功能的:
在使用方面,与synchronized的自动加锁解锁不同的是,ReentrantLock是需要在应用代码中显式进行加锁和解锁操作的,通常需要结合try-finally来实现,避免异常是无法解锁,如下:
class X {
private final ReentrantLock lock = new ReentrantLock();
// ...
public void m() {
lock.lock(); // block until condition holds
try {
// ... method body
} finally {
lock.unlock()
}
}
}
公平版本:
/**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
*/
// 判断当前线程是否可以访问共享资源,返回true或false,
// 在AQS的acquire方法中定义了模板实现,即调用了tryAcquire,
// 该方法返回false,则在acquire中调用acquireQueued方法将当前线程节点放入等待队列中
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;
}
}
// 递增state,实现可重入
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
非公平版本:
/**
* Sync object for non-fair locks
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
/**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
// 先尝试获取,实现非公平
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
// 在基类Sync中定义,Sync继承AbstractQueuedSynchronizer
/**
* Performs non-fair tryLock. tryAcquire is implemented in
* subclasses, but both need nonfair try for trylock method.
*/
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
// 先尝试获取,失败返回false则入队,实现非公平
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
// 递增state,实现可重入
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;
}
在基类Sync中定义,Sync继承AbstractQueuedSynchronizer:递减state直到0
protected final boolean tryRelease(int releases) {
// 递减state
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
// state等于0,则释放锁
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
阻塞加锁直到获取锁为止,与synchronized语义一样,不支持中断、超时:
/**
* Acquires the lock.
*
* Acquires the lock if it is not held by another thread and returns
* immediately, setting the lock hold count to one.
*
*
If the current thread already holds the lock then the hold
* count is incremented by one and the method returns immediately.
*
*
If the lock is held by another thread then the
* current thread becomes disabled for thread scheduling
* purposes and lies dormant until the lock has been acquired,
* at which time the lock hold count is set to one.
*/
public void lock() {
sync.lock();
}
阻塞可中断版本:
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
非阻塞版本:非阻塞,非公平,即使使用的是公平锁,能获取锁则返回true,否则返回false。
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
阻塞可超时版本:阻塞指定时间,若在该指定时间到达之后,还没获取锁,则返回false:
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
synchronized的wait的语义为:线程占有锁,发现条件不满足,释放锁,线程阻塞休眠,进入条件化等待队列,等待其他线程notify唤醒。
Lock的await的调用也是跟synchronized的wait一样,首先对应的线程需要获取Lock锁进入同步代码,即如果方法没有先调用如lock.lock()获取锁的情况下,调用await了,则会抛IllegalMonitorStateException异常。
await对synchronized的wait的语义实现如下:将当前线程放入条件化等待队列,然后释放锁,在while循环内阻塞休眠,直到被放到AQS同步队列了,这时说明条件满足了,可以去竞争获取锁了,通过调用acquireQueued去竞争获取锁。如果获取锁成功了,则真正从await返回。
/**
* Implements interruptible condition wait.
*
* - If current thread is interrupted, throw InterruptedException.
*
- Save lock state returned by {@link #getState}.
*
- Invoke {@link #release} with saved state as argument,
* throwing IllegalMonitorStateException if it fails.
*
- Block until signalled or interrupted.
*
- Reacquire by invoking specialized version of
* {@link #acquire} with saved state as argument.
*
- If interrupted while blocked in step 4, throw InterruptedException.
*
*/
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
// 进入条件化等待队列
Node node = addConditionWaiter();
// 释放锁
int savedState = fullyRelease(node);
int interruptMode = 0;
// 自旋检查是否被放到同步队列了
while (!isOnSyncQueue(node)) {
// 阻塞休眠线程
LockSupport.park(this);
// 在等待队列中被中断,则退出等待
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
// 被其他线程通过signal唤醒了,则放到同步队列合适的位置,
// 等待重新获取锁,从而从该await方法返回,继续执行
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null) // clean up if cancelled
unlinkCancelledWaiters();
// 唤醒被获取锁之后,再检查是否之前被中断过,补上中断
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
在应用代码中,await通常需要在while循环中检查条件是否满足,只有对应线程被唤醒,获取锁成功,然后再在while循环检查条件是否满足,如果满足,则继续执行,因为此时只有当前线程占有锁,不会出现并发修改导致条件不满足,如下为LinkedBlockingQueue的put的实现:
public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
// Note: convention in all put/take/etc is to preset local var
// holding count negative to indicate failure unless set.
int c = -1;
Node<E> node = new Node<E>(e);
final ReentrantLock putLock = this.putLock;
final AtomicInteger count = this.count;
putLock.lockInterruptibly();
try {
/*
* Note that count is used in wait guard even though it is
* not protected by lock. This works because count can
* only decrease at this point (all other puts are shut
* out by lock), and we (or some other waiting put) are
* signalled if it ever changes from capacity. Similarly
* for all other uses of count in other wait guards.
*/
// 阻塞直到数据队列存在空间可以存放数据
while (count.get() == capacity) {
notFull.await();
}
enqueue(node);
c = count.getAndIncrement();
// 可能同时存在多个生产者在写,故通知下一个生产者继续写
if (c + 1 < capacity)
notFull.signal();
} finally {
putLock.unlock();
}
// 可能之前为空,故写数据进去之后分空了,故通知等待非空的消费者来读取
if (c == 0)
signalNotEmpty();
}
可中断阻塞等待
/**
* Implements interruptible condition wait.
*
* - If current thread is interrupted, throw InterruptedException.
*
- Save lock state returned by {@link #getState}.
*
- Invoke {@link #release} with saved state as argument,
* throwing IllegalMonitorStateException if it fails.
*
- Block until signalled or interrupted.
*
- Reacquire by invoking specialized version of
* {@link #acquire} with saved state as argument.
*
- If interrupted while blocked in step 4, throw InterruptedException.
*
*/
public final void await() throws InterruptedException
可中断,可超时阻塞等待:分别为基于纳秒,指定日期,自定义时间单位的版本
/**
* Implements timed condition wait.
*
* - If current thread is interrupted, throw InterruptedException.
*
- Save lock state returned by {@link #getState}.
*
- Invoke {@link #release} with saved state as argument,
* throwing IllegalMonitorStateException if it fails.
*
- Block until signalled, interrupted, or timed out.
*
- Reacquire by invoking specialized version of
* {@link #acquire} with saved state as argument.
*
- If interrupted while blocked in step 4, throw InterruptedException.
*
*/
public final long awaitNanos(long nanosTimeout)
throws InterruptedException
/**
* Implements absolute timed condition wait.
*
* - If current thread is interrupted, throw InterruptedException.
*
- Save lock state returned by {@link #getState}.
*
- Invoke {@link #release} with saved state as argument,
* throwing IllegalMonitorStateException if it fails.
*
- Block until signalled, interrupted, or timed out.
*
- Reacquire by invoking specialized version of
* {@link #acquire} with saved state as argument.
*
- If interrupted while blocked in step 4, throw InterruptedException.
*
- If timed out while blocked in step 4, return false, else true.
*
*/
public final boolean awaitUntil(Date deadline) throws InterruptedException
/**
* Implements timed condition wait.
*
* - If current thread is interrupted, throw InterruptedException.
*
- Save lock state returned by {@link #getState}.
*
- Invoke {@link #release} with saved state as argument,
* throwing IllegalMonitorStateException if it fails.
*
- Block until signalled, interrupted, or timed out.
*
- Reacquire by invoking specialized version of
* {@link #acquire} with saved state as argument.
*
- If interrupted while blocked in step 4, throw InterruptedException.
*
- If timed out while blocked in step 4, return false, else true.
*
*/
public final boolean await(long time, TimeUnit unit) throws InterruptedException
signal主要是当前占有锁正在执行的线程,在条件满足时,通知和唤醒该Condition对应的条件化等待队列的一个线程,让该线程去竞争获取锁,然后继续执行。
Condition的signal实现主要是将Condition对应的条件化等待队列的头结点移到到AQS的同步队列中,具体为移动到同步队列的尾部,这样这个节点对应的线程就可以去竞争锁了。如下:
/**
* Moves the longest-waiting thread, if one exists, from the
* wait queue for this condition to the wait queue for the
* owning lock.
*
* @throws IllegalMonitorStateException if {@link #isHeldExclusively}
* returns {@code false}
*/
public final void signal() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
// 条件化等待队列的头结点
Node first = firstWaiter;
if (first != null)
doSignal(first);
}
/**
* Removes and transfers nodes until hit non-cancelled one or
* null. Split out from signal in part to encourage compilers
* to inline the case of no waiters.
* @param first (non-null) the first node on condition queue
*/
private void doSignal(Node first) {
do {
if ( (firstWaiter = first.nextWaiter) == null)
lastWaiter = null;
first.nextWaiter = null;
} while (!transferForSignal(first) &&
(first = firstWaiter) != null);
}
/**
* Transfers a node from a condition queue onto sync queue.
* Returns true if successful.
* @param node the node
* @return true if successfully transferred (else the node was
* cancelled before signal)
*/
final boolean transferForSignal(Node node) {
/*
* If cannot change waitStatus, the node has been cancelled.
*/
// 将节点的waitStatus从CONDITION修改为0,
// 0是添加到同步队列的节点的初始化状态
if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
return false;
/*
* Splice onto queue and try to set waitStatus of predecessor to
* indicate that thread is (probably) waiting. If cancelled or
* attempt to set waitStatus fails, wake up to resync (in which
* case the waitStatus can be transiently and harmlessly wrong).
*/
// 将该节点添加到同步队列尾部,
// 并将前置节点的waitStatus设置为SIGNAL,
// 从而使得该前置节点知道后面有节点在排队等待获取锁
// 在应用代码中,当执行完signal之后,一般接下来的代码为lock.unlock()释放锁,
// unlock内部调用release方法,从这个同步队列唤醒下一个执行的线程,
// 所以当前这个刚刚被移到同步队列的线程就可能是这个执行的线程了。
Node p = enq(node);
int ws = p.waitStatus;
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
LockSupport.unpark(node.thread);
return true;
}
在使用方面,signal不需要在while循环中,因为调用signal的线程是当前占有锁,正在执行的线程。