ReentrantLock类的继承关系
public class ReentrantLock implements Lock, java.io.Serializable {}
ReentrantLock实现了Lock接口,并且实现了java.io.Serializable接口,具有了序列化的能力.
Lock接口源码如下.
public interface Lock {
/**
* Acquires the lock.
*
* <p>If the lock is not available then the current thread becomes
* disabled for thread scheduling purposes and lies dormant until the
* lock has been acquired.
*
* <p><b>Implementation Considerations</b>
*
* <p>A {@code Lock} implementation may be able to detect erroneous use
* of the lock, such as an invocation that would cause deadlock, and
* may throw an (unchecked) exception in such circumstances. The
* circumstances and the exception type must be documented by that
* {@code Lock} implementation.
*/
void lock();//加锁方法.
/**
* Acquires the lock unless the current thread is
* {@linkplain Thread#interrupt interrupted}.
*
* <p>Acquires the lock if it is available and returns immediately.
*
* <p>If the lock is not available then the current thread becomes
* disabled for thread scheduling purposes and lies dormant until
* one of two things happens:
*
* <ul>
* <li>The lock is acquired by the current thread; or
* <li>Some other thread {@linkplain Thread#interrupt interrupts} the
* current thread, and interruption of lock acquisition is supported.
* </ul>
*
* <p>If the current thread:
* <ul>
* <li>has its interrupted status set on entry to this method; or
* <li>is {@linkplain Thread#interrupt interrupted} while acquiring the
* lock, and interruption of lock acquisition is supported,
* </ul>
* then {@link InterruptedException} is thrown and the current thread's
* interrupted status is cleared.
*
* <p><b>Implementation Considerations</b>
*
* <p>The ability to interrupt a lock acquisition in some
* implementations may not be possible, and if possible may be an
* expensive operation. The programmer should be aware that this
* may be the case. An implementation should document when this is
* the case.
*
* <p>An implementation can favor responding to an interrupt over
* normal method return.
*
* <p>A {@code Lock} implementation may be able to detect
* erroneous use of the lock, such as an invocation that would
* cause deadlock, and may throw an (unchecked) exception in such
* circumstances. The circumstances and the exception type must
* be documented by that {@code Lock} implementation.
*
* @throws InterruptedException if the current thread is
* interrupted while acquiring the lock (and interruption
* of lock acquisition is supported)
*/
void lockInterruptibly() throws InterruptedException;//可中断加锁.
/**
* Acquires the lock only if it is free at the time of invocation.
*
* <p>Acquires the lock if it is available and returns immediately
* with the value {@code true}.
* If the lock is not available then this method will return
* immediately with the value {@code false}.
*
* <p>A typical usage idiom for this method would be:
* <pre> {@code
* Lock lock = ...;
* if (lock.tryLock()) {
* try {
* // manipulate protected state
* } finally {
* lock.unlock();
* }
* } else {
* // perform alternative actions
* }}</pre>
*
* This usage ensures that the lock is unlocked if it was acquired, and
* doesn't try to unlock if the lock was not acquired.
*
* @return {@code true} if the lock was acquired and
* {@code false} otherwise
*/
boolean tryLock();//返回是否加锁成功.
/**
* Acquires the lock if it is free within the given waiting time and the
* current thread has not been {@linkplain Thread#interrupt interrupted}.
*
* <p>If the lock is available this method returns immediately
* with the value {@code true}.
* If the lock is not available then
* the current thread becomes disabled for thread scheduling
* purposes and lies dormant until one of three things happens:
* <ul>
* <li>The lock is acquired by the current thread; or
* <li>Some other thread {@linkplain Thread#interrupt interrupts} the
* current thread, and interruption of lock acquisition is supported; or
* <li>The specified waiting time elapses
* </ul>
*
* <p>If the lock is acquired then the value {@code true} is returned.
*
* <p>If the current thread:
* <ul>
* <li>has its interrupted status set on entry to this method; or
* <li>is {@linkplain Thread#interrupt interrupted} while acquiring
* the lock, and interruption of lock acquisition is supported,
* </ul>
* then {@link InterruptedException} is thrown and the current thread's
* interrupted status is cleared.
*
* <p>If the specified waiting time elapses then the value {@code false}
* is returned.
* If the time is
* less than or equal to zero, the method will not wait at all.
*
* <p><b>Implementation Considerations</b>
*
* <p>The ability to interrupt a lock acquisition in some implementations
* may not be possible, and if possible may
* be an expensive operation.
* The programmer should be aware that this may be the case. An
* implementation should document when this is the case.
*
* <p>An implementation can favor responding to an interrupt over normal
* method return, or reporting a timeout.
*
* <p>A {@code Lock} implementation may be able to detect
* erroneous use of the lock, such as an invocation that would cause
* deadlock, and may throw an (unchecked) exception in such circumstances.
* The circumstances and the exception type must be documented by that
* {@code Lock} implementation.
*
* @param time the maximum time to wait for the lock
* @param unit the time unit of the {@code time} argument
* @return {@code true} if the lock was acquired and {@code false}
* if the waiting time elapsed before the lock was acquired
*
* @throws InterruptedException if the current thread is interrupted
* while acquiring the lock (and interruption of lock
* acquisition is supported)
*/
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
/**
* Releases the lock.
*
* <p><b>Implementation Considerations</b>
*
* <p>A {@code Lock} implementation will usually impose
* restrictions on which thread can release a lock (typically only the
* holder of the lock can release it) and may throw
* an (unchecked) exception if the restriction is violated.
* Any restrictions and the exception
* type must be documented by that {@code Lock} implementation.
*/
void unlock();//解锁.
/**
* Returns a new {@link Condition} instance that is bound to this
* {@code Lock} instance.
*
* <p>Before waiting on the condition the lock must be held by the
* current thread.
* A call to {@link Condition#await()} will atomically release the lock
* before waiting and re-acquire the lock before the wait returns.
*
* <p><b>Implementation Considerations</b>
*
* <p>The exact operation of the {@link Condition} instance depends on
* the {@code Lock} implementation and must be documented by that
* implementation.
*
* @return A new {@link Condition} instance for this {@code Lock} instance
* @throws UnsupportedOperationException if this {@code Lock}
* implementation does not support conditions
*/
Condition newCondition();//创建一个条件队列.
}
可以看出ReentrantLock是根据lock接口定义的规范来实现的加锁解锁.
内部类
ReentrantLock总共有三个内部类,关系如下.
Sync类
源码如下.
/**
* Base of synchronization control for this lock. Subclassed
* into fair and nonfair versions below. Uses AQS state to
* represent the number of holds on the lock.
*/
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
/**
* Performs {@link Lock#lock}. The main reason for subclassing
* is to allow fast path for nonfair version.
*/
abstract void lock();//获取锁.
/**
* 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) {//未获取锁.
if (compareAndSetState(0, acquires)) {//CAS操作获取锁,改变状态
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;
}
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;
}
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;
}
final boolean isLocked() {//是否获取锁.
return getState() != 0;
}
/**
* Reconstitutes the instance from a stream (that is, deserializes it).
*/
private void readObject(java.io.ObjectInputStream s)//自定义反序列化逻辑
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // reset to unlocked state
}
}
Sync类存在如下方法和作用.
NonfairSync类
源码如下.
/**
* 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))//CAS获取锁成功改变状态,设置占锁线程.
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);//加锁失败
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
/**
* Acquires in exclusive mode, ignoring interrupts. Implemented
* by invoking at least once {@link #tryAcquire},
* returning on success. Otherwise the thread is queued, possibly
* repeatedly blocking and unblocking, invoking {@link
* #tryAcquire} until success. This method can be used
* to implement method {@link Lock#lock}.
*
* @param arg the acquire argument. This value is conveyed to
* {@link #tryAcquire} but is otherwise uninterpreted and
* can represent anything you like.
*/
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
加锁失败了,就是AQS队列的逻辑了.不理解的话可以看一下上篇AQS的讲解.
从lock方法的源码可知,每一次都尝试获取锁,而并不会按照公平等待的原则进行等待,让等待时间最久的线程获得锁。
FairSyn类
源码如下.
/**
* Sync object for fair locks
*/
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {//获取锁.
acquire(1);
}
/**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
*/
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;
}
}
/**
* Queries whether any threads have been waiting to acquire longer
* than the current thread.
*
* <p>An invocation of this method is equivalent to (but may be
* more efficient than):
* <pre> {@code
* getFirstQueuedThread() != Thread.currentThread() &&
* hasQueuedThreads()}</pre>
*
* <p>Note that because cancellations due to interrupts and
* timeouts may occur at any time, a {@code true} return does not
* guarantee that some other thread will acquire before the current
* thread. Likewise, it is possible for another thread to win a
* race to enqueue after this method has returned {@code false},
* due to the queue being empty.
*
* <p>This method is designed to be used by a fair synchronizer to
* avoid <a href="AbstractQueuedSynchronizer#barging">barging</a>.
* Such a synchronizer's {@link #tryAcquire} method should return
* {@code false}, and its {@link #tryAcquireShared} method should
* return a negative value, if this method returns {@code true}
* (unless this is a reentrant acquire). For example, the {@code
* tryAcquire} method for a fair, reentrant, exclusive mode
* synchronizer might look like this:
*
* <pre> {@code
* protected boolean tryAcquire(int arg) {
* if (isHeldExclusively()) {
* // A reentrant acquire; increment hold count
* return true;
* } else if (hasQueuedPredecessors()) {
* return false;
* } else {
* // try to acquire normally
* }
* }}</pre>
*
* @return {@code true} if there is a queued thread preceding the
* current thread, and {@code false} if the current thread
* is at the head of the queue or the queue is empty
* @since 1.7
*/
public final boolean hasQueuedPredecessors() {
// The correctness of this depends on head being initialized
// before tail and on head.next being accurate if the current
// thread is first in queue.
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
从这个方法可以看出来是按照顺序来获取锁.
FairSync类的lock的方法调用.
可以看出只要资源被其他线程占用,该线程就会添加到sync queue中的尾部,而不会先尝试获取资源。这也是和Nonfair最大的区别,Nonfair每一次都会尝试去获取资源,如果此时该资源恰好被释放,则会被当前线程获取,这就造成了不公平的现象,当获取不成功,再加入队列尾部.
属性
public class ReentrantLock implements Lock, java.io.Serializable {
// 序列号
private static final long serialVersionUID = 7373984872572414699L;
// 同步队列
private final Sync sync;
}
构造函数
public ReentrantLock() {
// 默认非公平策略
sync = new NonfairSync();
}
默认是采用的非公平策略获取锁.
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
可以传递参数确定采用公平策略或者是非公平策略,参数为true表示公平策略,否则,采用非公平策略.
公平锁示例
public class ReentrantLockThread extends Thread {
private Lock lock;
public ReentrantLockThread(String name, Lock lock) {
super(name);
this.lock = lock;
}
@Override
public void run() {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + " running");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
Lock lock = new ReentrantLock(true);
ReentrantLockThread t1 = new ReentrantLockThread("t1", lock);
ReentrantLockThread t2 = new ReentrantLockThread("t2", lock);
ReentrantLockThread t3 = new ReentrantLockThread("t3", lock);
t1.start();
t2.start();
t3.start();
}
}}
}
运行结果.(其中之一)
该示例使用的是公平策略,由结果可知.
t1线程的lock操作 -> t2线程的lock操作 -> t3线程的lock操作 -> t1线程的unlock操作 -> t2线程的unlock操作 -> t3线程的unlock操作.
t1线程执行lock.lock.
t2线程执行lock.lock
t3线程执行lock.lock
t1线程调用了lock.unlock
t2获得cpu资源,继续运行,由于t2之前被park了,现在需要恢复之前的状态 .
t2执行lock.unlock
t3线程获取cpu资源,恢复之前的状态,继续运行
t3执行lock.unlock
最后的状态和之前的状态是一样的,队列中有一个空节点,头节点为尾节点均指向它。