java并发编程之美 学习笔记
独占锁 ReentrantLock
结构
public class ReentrantLock implements Lock, java.io.Serializable {
private final Sync sync;
//Sync 类直接继承自 AQS ,
abstract static class Sync extends AbstractQueuedSynchronizer {
}
//非公平锁
static final class NonfairSync extends Sync {
}
//公平锁
static final class FairSync extends Sync {
}
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
}
在这里,AQS中的state
表示线程获取锁的可重入次数
.
state == 0
,表示当前锁没有被任何线程持有- 当一个线程第一次获取锁时,会使用
CAS
设置state为1
,当CAS操作成功时,记录该锁的持有者为当前线程。 - 在该线程获取锁并没有释放的情况下,第二次获取锁后,state状态值+1,在线程释放锁时state值-1,当state值再次为0时,表示当前线程释放锁.
获取锁
public void lock() {
//委托给sync,根据构造函数选择:公平or非公平锁
sync.lock();
}
非公平锁
//java.util.concurrent.locks.ReentrantLock.NonfairSync
static final class NonfairSync extends Sync {
final void lock() {
//cas操作尝试设置state == 1
if (compareAndSetState(0, 1))
//如果cas操作成功,设置lock当前持有者 为当前线程
setExclusiveOwnerThread(Thread.currentThread());
else
//1.调用AQS的acquire方法
acquire(1);
}
//2.
protected final boolean tryAcquire(int acquires) {
//3. 由父类Sync实现
return nonfairTryAcquire(acquires);
}
}
//java.util.concurrent.locks.AbstractQueuedSynchronizer
//1
public final void acquire(int arg) {
//2.尝试获取锁--由子类实现
if (!tryAcquire(arg) &&
//如果尝试获取失败,则将当前线程加入阻塞队列
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
//java.util.concurrent.locks.ReentrantLock.Sync
//3.
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
//c == 0 ,表示当前锁为空闲状态
if (compareAndSetState(0, acquires)) {
//设置当前线程为锁的持有者
setExclusiveOwnerThread(current);
return true;
}
}
// c != 0 ,但锁的持有者为当前线程
else if (current == getExclusiveOwnerThread()) {
//计算并更新 state
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
//否则返回false
return false;
}
公平锁
//java.util.concurrent.locks.ReentrantLock.fairSync
static final class FairSync extends Sync {
final void lock() {
//aqs内部调用tryAcquire
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
/**
* hasQueuedPredecessors(): aqs等待队列中head.next 指定的node持有的线程是否为当前线程
* 即当前线程锁持有node,是否为第一个等待队列中第一个node(除去head的第一个)
* 如果是第一个,返回false, 进行2
* 如果不是,返回true,跳出逻辑, 整个方法 返回false,即获取失败
*/
if (!hasQueuedPredecessors() && //1
compareAndSetState(0, acquires)) {//2 cas设置state
//设置当前线程为锁的持有者
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;
}
}
//java.util.concurrent.locks.AbstractQueuedSynchronizer
public final boolean hasQueuedPredecessors() {
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
//h.next 表示head指向的第一个元素, 判断它持有的线程是否为当前线程
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
公平与非公平
公平锁
: 它是按照线程在aqs等待队列中的时间先后顺序
来依次获取锁的。非公平锁
: 它是抢夺策略
来获取锁的,如下图:
释放锁
- 如果当前线程持有该锁 ,则更新AQS的state-1,如果减去1后当前状态值为 0,则当前线程会释放该锁,否则线程依然持有锁。
- 如果未持有锁的线程,执行释放锁的操作,则抛出异常
IllegalMonitorStateException
//java.util.concurrent.locks.ReentrantLock
public void unlock() {
//1.委托sync执行释放操作,该方法由AQS实现;
sync.release();
}
//java.util.concurrent.locks.AbstractQueuedSynchronizer
public final boolean release(int arg) {
//2. tryRelease由子类Sync实现
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
//3. 从等待队列head头部开始寻找第一个不为空的node
//调用LockSupport.unpark()唤醒之。
unparkSuccessor(h);
return true;
}
return false;
}
//java.util.concurrent.locks.AbstractQueuedSynchronizer.Sync
//3
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;
//当执行递减操作后,state == 0 ,释放锁,更新持有锁线程为null;
//free = true
setExclusiveOwnerThread(null);
}
//如果state != 0 ,仅执行更新,并不释放锁; free = false
setState(c);
return free;
}