我们先跟踪非公平锁加锁和释放锁的大概流程,有一个基本的印象。
public class LockTest {
private Lock lock = new ReentrantLock();
public void lockTest() {
lock.lock();
try {
System.out.println("lock test");
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
LockTest test = new LockTest();
new Thread() {
@Override
public void run() {
test.lockTest();
}
}.start();
new Thread() {
@Override
public void run() {
test.lockTest();
}
}.start();
}
}
先看下默认的构造方法:
/**
* Creates an instance of {@code ReentrantLock}.
* This is equivalent to using {@code ReentrantLock(false)}.
*/
// 创建一个实例,等同于调用 new ReentrantLock(false),返回非公平锁的实例
public ReentrantLock() {
sync = new NonfairSync();
}
在上面的构造方法中,创建了NonfairSync 对象赋值给成员变量 sync
public class ReentrantLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = 7373984872572414699L;
/** Synchronizer providing all implementation mechanics */
private final Sync sync;
....
....
}
由此可以看出NonfairSync 是Sync 的一个子类
/**
* 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 是什么东西
/**
* 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.
*/
// 锁同步控制的基础。子类包括公平锁和非公平锁。利用AQS 的状态来表示锁持有的次数
abstract static class Sync extends AbstractQueuedSynchronizer {
...
...
...
}
Sync 继承了AbstractQueuedSynchronizer,也就是上面类注释中的AQS,并且知道锁的控制流程跟AQS 的state 有关。
再来理一下,创建一个ReentrantLock,会间接持有一个AbstractQueuedSynchronizer 实现类的引用,也就是我们常说的AQS,接下来的加锁跟释放锁操作,都跟AQS 或者其子类有关。
先看一下ReentrantLock.lock() 方法
/**
* Acquires the lock.
//获得锁
*
* <p>Acquires the lock if it is not held by another thread and returns
* immediately, setting the lock hold count to one.
//如果锁没有被其他线程持有就可以获得,并且立即返回,然后设置锁的持有计数为1
*
* <p>If the current thread already holds the lock then the hold
* count is incremented by one and the method returns immediately.
//如果当前线程已经获得锁,锁的持有计数就会增加1,并且立即返回
*
* <p>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.
// 如果锁被其他线程持有,当前线程就会被禁用并且休眠,直到锁被获取,获取到之后,锁的持有计数设置为1
*/
public void lock() {
sync.lock();
}
跟踪代码,发现调用的是NonfairSync.lock(),看下代码
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);
}
...
...
}
方法compareAndSetState(0, 1) 来自父类AQS,实际上调用的是CAS
/**
* Atomically sets synchronization state to the given updated
* value if the current state value equals the expected value.
* This operation has memory semantics of a {@code volatile} read
* and write.
*
* @param expect the expected value
* @param update the new value
* @return {@code true} if successful. False return indicates that the actual
* value was not equal to the expected value.
*/
protected final boolean compareAndSetState(int expect, int update) {
// See below for intrinsics setup to support this
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
这下对于获取锁这个操作就比较明朗了,底层使用CAS,保证线程安全。线程A 进来先调用compareAndSetState(0, 1),判断当前锁的计数状态是不是0,是0的话,就将锁的计数状态变成1,返回true,相当于获得一把锁,此时线程B进来,继续调用compareAndSetState(0, 1),由于此时锁的计数状态是1,不等于0,返回false,相当于锁获取失败,走到acquire(1) 代码分支,进行排队,acquire(1) 方法先不讲细节,只需要先知道在这个方法中,其他线程会一直排队,直到获取锁。
到此大方向跟完了ReentrantLock.lock() 方法,接下来继续跟踪ReentrantLock.unlock()
/**
* Attempts to release this lock.
//尝试释放锁
*
* <p>If the current thread is the holder of this lock then the hold
* count is decremented. If the hold count is now zero then the lock
* is released. If the current thread is not the holder of this
* lock then {@link IllegalMonitorStateException} is thrown.
//如果当前线程持有锁,则锁的计数状态-1。如果锁的计数状态为0,说明锁已经释放了。如果当前线程没持有锁,就会抛异常
*
* @throws IllegalMonitorStateException if the current thread does not
* hold this lock
*/
public void unlock() {
sync.release(1);
}
继续跟下去,发现调用的是AQS 的release() 方法
/**
* Releases in exclusive mode. Implemented by unblocking one or
* more threads if {@link #tryRelease} returns true.
* This method can be used to implement method {@link Lock#unlock}.
*
* @param arg the release argument. This value is conveyed to
* {@link #tryRelease} but is otherwise uninterpreted and
* can represent anything you like.
* @return the value returned from {@link #tryRelease}
*/
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
继续跟tryRelease(arg) 方法,这个方法必须是子类实现的,因此我们去看下Sync 中的实现
abstract static class Sync extends AbstractQueuedSynchronizer {
...
...
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;
}
}
tryRelease 方法中,将锁计数状态减少并重新赋值。也就是说,lock() 方法会增加锁计数状态,unlock() 会减少锁的计数状态,刚好印证前面说的锁的控制流程跟AQS 中的state 有关。
本章先大致跟踪一下非公平锁加锁跟释放锁的流程,并没有深入跟踪比如锁的排队机制、公平锁和公平锁各自的实现差异、锁可打断的原理实现等,后续咱们带着这些疑问一个一个去跟踪。