相关阅读
- JUC源码简析 AbstractQueuedSynchronizer
- JUC源码简析 Condition
- JUC源码简析 CountDownLatch
- JUC源码简析 CyclicBarrier
- JUC源码简析 Semaphore
简介
支持重进入的独占锁,使用内部持有的Sync
类型的实例实现了Lock
接口。
内部类Sync
继承自AbstractQueuedSynchronizer
,重写了父类的tryRelease
和isHeldExclusively
方法;定义抽象方法lock()
,由子类实现;
内部类FairSync
继承自Sync
,以公平(先到先得)竞争锁的方式实现了lock()
算法字节;
内部类NonfairSync
继承自Sync
,以非公平(不保证先到先得)竞争锁的方式实现了lock()
算法细节;
源码简析
内部类——Sync
简介
重写了父类的tryRelease
和isHeldExclusively
方法;
定义抽象方法lock()
,由子类实现;
abstract void lock();
tryRelease
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
// 校验释放锁的线程是否时持有锁的线程
if (Thread.currentThread() != getExclusiveOwnerThread())
// 当前线程不是持有独占锁的线程,那么就是非法操作,需要抛出IllegalMonitorStateException
throw new IllegalMonitorStateException();
// 释放锁标识,默认未释放
boolean free = false;
if (c == 0) {
// 资源为0,则表示本线程已释放锁
free = true;
// 清空持有锁线程信息
setExclusiveOwnerThread(null);
}
// 更新锁资源
setState(c);
return free;
}
本方法只支持被持有独占锁的线程调用,所以不存在线程竞争,其它线程调用则会抛出异常IllegalMonitorStateException
;
isHeldExclusively
protected final boolean isHeldExclusively() {
// 持有锁的线程是否是本线程
return getExclusiveOwnerThread() == Thread.currentThread();
}
nonfairTryAcquire
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
// 如果当前锁资源还未被占用
if (c == 0) {
// CAS尝试获取锁资源,存在多线程竞争
if (compareAndSetState(0, acquires)) {
// 获取成功,设置本线程为持有锁线程
setExclusiveOwnerThread(current);
// true表示获取锁成功
return true;
}
}
// 锁资源已经被占用,则考虑是不是被自身占有的
else if (current == getExclusiveOwnerThread()) {
// 可重入的体现
// 累加锁资源计数
int nextc = c + acquires;
if (nextc < 0)
// 资源计数发生反转,需要抛出错误
throw new Error("Maximum lock count exceeded");
// 更新锁资源
setState(nextc);
// true表示获取锁成功
return true;
}
// false表示获取锁成功
return false;
}
本方式是以不公平竞争锁的方式实现的,不公平的体现为:新线程没有考虑当前是否已存在其它线程在等待获取锁,而是直接尝试获取锁;如果此时持有锁的线程恰好释放锁,那么新线程就可能获取锁成功,被释放锁线程唤醒的后继节点线程会因获取锁失败,再次设置头节点(头节点没有变化)的等待状态为SIGNAL
,然后挂起,等待新线程释放锁时唤醒自身;
内部类——NonFairSync
简介
继承自Sync
,实现非公平锁相关操作;
需要实现的方法为:
- 父类
Sync
的抽象方法lock
; - 来自父类
Sync
继承的AbstractQueuedSynchronizer
的抽象方法tryAcquire
;
lock
final void lock() {
// CAS尝试获取独占锁,即假设锁资源还未被获取,然后占取锁资源
if (compareAndSetState(0, 1))
// 获取成功,设置本线程为持有锁线程
setExclusiveOwnerThread(Thread.currentThread());
else
// 老老实实地获取锁
acquire(1);
}
tryAcquire
protected final boolean tryAcquire(int acquires) {
// 调用父类Sync的nonfaireTryAcquire实现
return nonfairTryAcquire(acquires);
}
本方式是以不公平竞争锁的方式实现的,不公平的体现为:新线程没有考虑当前是否已存在其它线程在等待获取锁,而是直接尝试快速获取锁;如果此时持有锁的线程恰好释放锁,那么新线程就可能获取锁成功,被释放锁线程唤醒的后继节点线程会因获取锁失败,再次设置头节点(头节点没有变化)的等待状态为SIGNAL
,然后挂起,等待新线程释放锁时唤醒自身;新线程尝试快速获取锁失败后,才老实地按照正常方式去获取锁;
内部类——FairSync
简介
继承自Sync
,实现公平锁相关操作;
需要实现的方法为:
- 父类
Sync
的抽象方法lock
; - 来自父类
Sync
继承的AbstractQueuedSynchronizer
的抽象方法tryAcquire
;
lock
final void lock() {
// 老老实实地获取锁,没有尝试快速获取锁
acquire(1);
}
tryAcquire
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
// 如果当前锁资源还未被占用
if (c == 0) {
// 不存在等待获取锁的线程,才CAS尝试获取锁资源,存在多线程竞争
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
// 获取成功,设置本线程为持有锁线程
setExclusiveOwnerThread(current);
// true表示获取锁成功
return true;
}
}
// 锁资源已经被占用,则考虑是不是被自身占有的
else if (current == getExclusiveOwnerThread()) {
// 可重入的体现
// 累加锁资源计数
int nextc = c + acquires;
if (nextc < 0)
// 资源计数发生反转,需要抛出错误
throw new Error("Maximum lock count exceeded");
// 更新锁资源
setState(nextc);
// true表示获取锁成功
return true;
}
// false表示获取锁成功
return false;
}
// AbstractQueuedSynchronizer
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;
// 头节点就是尾节点,则队列没有其它等待节点
// 队列存在节点,且
// 头节点的next不存在,即此时有新节点插入队列,刚更新尾节点,还未来得及更新旧尾节点的next,那么队列中存在其它等待节点(新节点)
// 或者存在但不是本线程,那么队列中有其它等待节点
// 否则,不存在其它等待节点,因为头节点的next就是本线程节点,这是等待队列中的节点线程尝试获取锁的情况
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
本方式是以公平竞争锁的方式实现的,公平的体现为:新线程在尝试获取锁之前,会先考虑当前是否已存在其它线程在等待获取锁,如果存在则直接放弃获取锁;如果不存在,才尝试获取锁;
ReentrantLock
简介
实现了Lock
接口,Lock
接口的相关方法都是通过内部类Sync
的实例实现;
构造方法
public ReentrantLock() {
// 默认是非公平锁,使用场景更多
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
Lock接口
public void lock() {
sync.lock();
}
public void unlock() {
sync.release(1);
}
public Condition newCondition() {
return sync.newCondition();
}
测试
Demo
public class Demo {
private int parties = 5;
private ReentrantLock reentrantLock = new ReentrantLock();
public static void main(String[] args) throws InterruptedException {
Demo demo = new Demo();
ExecutorService es = Executors.newFixedThreadPool(demo.parties);
for (int i = 0; i < demo.parties; i++) {
es.execute(new ReentrantLockTask(i, demo.reentrantLock));
}
es.shutdown();
}
private static class ReentrantLockTask implements Runnable {
private ReentrantLock reentrantLock;
private int index;
ReentrantLockTask(int index, ReentrantLock reentrantLock) {
this.reentrantLock = reentrantLock;
this.index = index;
}
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(5);
System.out.println("Thread:" + index + " waits to get lock");
reentrantLock.lock();
System.out.println("Thread:" + index + " has get lock");
TimeUnit.SECONDS.sleep(5);
reentrantLock.unlock();
System.out.println("Thread:" + index + " has released lock");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
测试结果
Thread:0 waits to get lock
Thread:3 waits to get lock
Thread:2 waits to get lock
Thread:4 waits to get lock
Thread:1 waits to get lock
Thread:0 has get lock
Thread:0 has released lock
Thread:2 has get lock
Thread:2 has released lock
Thread:3 has get lock
Thread:3 has released lock
Thread:1 has get lock
Thread:1 has released lock
Thread:4 has get lock
Thread:4 has released lock