最近看了Java的并发包concurrent的ReentrantLock类源码,做下笔记。
二、ReentrantLock源码
三、AQS
1.!FairSync.tryAcquire(int acquires)//1为真,则表示没有获得锁,注意,前面有个"!"(非逻辑)
并且
2.AQS.acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
//Node.EXCLUSIVE就独占式锁,因为只有一个线程能获得锁,所以使用独占式锁;
//比如信号量Semaphore可以设置多个许可供给多个线程获得,则Semaphore会使用共享式锁Node.SHARED
(1和2)都为真 ==>>AQS.selfInterrupt()
//============================================================
FairSync.tryAcquire(int acquires)实现:
1.状态为0,则表示锁是空闲的
1.1 !AQS.hasQueuedPredecessors() //1.1为真,则表示等待队列里没有优先等待锁的线程节点
并且
1.2 AQS.compareAndSetState(0, 1) //使用CAS原子操作设置state值由0变为1
(1.1和1.2)都为真 ==>> 当前线程获得锁成功返回true。
2.状态不为0,则表示锁已被某个线程获得,
2.1判断锁的持有者是否当前线程
2.1.1是当前线程,则表示线程重复获得锁,将状态值state增加acquires,获得锁成功返回true。
2.1.2不是当前线程,尝试获得锁失败,返回false。
3. 返回false
//============================================================
总结:公平锁
线程请求获取锁时,判断状态state的值
1.当状态state为0时(即锁还没被线程占有),
1.1判断队列里有没前任优先线程节点,即,在当前线程之前有没其他线程在等待锁的释放
1.1.1如果没有优先线程,则当前线程可以获得锁
1.1.2如果有优先线程,则当前线程衔接在队尾阻塞等待锁空闲,等待其他线程唤醒来获得锁
2.当状态state不为0时,说明锁已经被某个线程占有,判断占有线程是否当前线程
2.1是当前线程,则线程可重复获得锁,将状态state值加1,表示线程又一次重复获得锁
2.2不是当前线程,则当前线程衔接在队尾阻塞等待锁空闲,等待其他线程唤醒来获得锁
//============================================================
总结:非公平锁
线程请求获取锁时,首先比其他线程优先获得锁(抢占式地,直接使用CAS(调用:compareAndSetState(0, 1))设置状态state值),
一、Lock接口
//在java的concurrent包中有个Lock接口,用来规范定义锁的行为public interface Lock{
/**
* 获得锁,如果锁不可用,当前线程会一直休眠(即使当前线程被其他线程中断的情况也会一直休眠)直到锁可获得。
*/
void lock();
/**
* 获得锁,如果锁不可用,当前线程会一直休眠直到当前线程被其他线程中断则会抛出InterruptedException异常。
*/
void lockInterruptibly() throws InterruptedException;
/**
* 锁是空闲的则立即返回true,如果锁是不可用的则立即返回false。
*/
boolean tryLock();
/**
* 如果锁可用,获得锁,返回true;
* 如果锁不可用,当前线程会一直休眠直到当前线程被其他线程中断则会抛出InterruptedException异常;
* 如果已经超过指定的时间,还没获得锁,返回false。
*/
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
/*
* 释放锁
*/
void unlock();
/*
* 返回一个绑定到当前Lock实例的Condition实例。
*/
Condition newCondition();
}
..
二、ReentrantLock源码
//===============================================================
进入主题,ReentrantLock源码
public class ReentrantLock implements Lock, java.io.Serializable {
private final Sync sync;
//同步器(很多功能继承于抽象类AbstractQueuedSynchronizer)
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)) {
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 this lock instance from a stream.
* @param s the stream
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // reset to unlocked state
}
}
//非公平锁的同步器
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.nonfairTryAcquire(int acquires)
}
}
//公平锁的同步器
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.
*/
//尝试获得锁,成功返回true,失败则返回false
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();//调用了AbstractQueuedSynchronizer.getStatus()==>>state
if (c == 0) { //state为0,表示没有线程获得锁
//!hasQueuedPredecessors():队列里没有排在当前线程之前的线程,
//compareAndSetState(0, acquires):则将锁的状态设置为已被获取
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;
}
}
}
..
三、AQS
//==========================================
其中锁背后真正的英雄是AQS(AbstractQueuedSynchronizer类,下面简称为AQS)的一些代码,当然,还有一些方法没写上来。
public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronzier{
static final class Node {
//表示线程已经取消
/** waitStatus value to indicate thread has cancelled */
static final int CANCELLED = 1;
//表示线程需要唤醒
/** waitStatus value to indicate successor's thread needs unparking */
static final int SIGNAL = -1;
/** waitStatus value to indicate thread is waiting on condition */
static final int CONDITION = -2;
/**
* waitStatus value to indicate the next acquireShared should
* unconditionally propagate
*/
static final int PROPAGATE = -3;
//waitStatus的值有:CANCELLED,SIGNAL,CONDITION,PROPAGATE
volatile int waitStatus;
//省略其他代码
}
//同步器的状态,volatile标识则保证了属性值的对多线程的可见性
private volatile int state;
//获得arg个许可
public final void acquire(int arg) {
//Node.EXCLUSIVE:线程节点标记为独占模式
if ( ! tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg) ) {
selfInterrupt();
}
}
//创建一个等待线程,插入队列
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;
if (pred != null) {//队尾不为空,则表示队尾已经被初始化
node.prev = pred;
if (compareAndSetTail(pred, node)) {//将当前线程节点衔接到队尾
pred.next = node;
return node;
}
}
//代码执行到这里,表示队尾为空,即队尾还没被初始化
enq(node);
return node;
}
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
private void unparkSuccessor(Node node) {
/*
* If status is negative (i.e., possibly needing signal) try
* to clear in anticipation of signalling. It is OK if this
* fails or if status is changed by waiting thread.
*/
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
/*
* Thread to unpark is held in successor, which is normally
* just the next node. But if cancelled or apparently null,
* traverse backwards from tail to find the actual
* non-cancelled successor.
*/
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
if (s != null)
LockSupport.unpark(s.thread);
}
//线程节点入队
private Node enq(final Node node) {
//如果队列还没被初始化,则初始化队头为(new Node()),队尾也指向队头
//然后将线程节点衔接到队尾
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))//使用CAS原子操作设置队头
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {//使用CAS原子操作设置队尾
t.next = node;
return t;
}
}
}
}
//队列里有优先获得锁的线程
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());
//队头head和队尾tail的指向不同
//(因为队列还没初始化时,head和tail都为null,队列刚初始化时,它们的指向也是相同的)
//队尾没有在排队的线程或者排在队尾的线程是其他线程
}
排队获得锁(CLH锁)
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();//排在线程节点前面的节点
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
//如果前趋节点p是正在阻塞等待锁的状态(shouldParkAfterFailedAcquire方法),则当前线程挂起(parkAndCheckInterrupt方法)。
if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
/**
* Checks and updates status for a node that failed to acquire.
* Returns true if thread should block. This is the main signal
* control in all acquire loops. Requires that pred == node.prev
*
* @param pred node's predecessor holding status
* @param node the node
* @return {@code true} if thread should block
*/
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL) //SIGNAL:-1,前趋节点的状态是需要唤醒的状态
/*
* This node has already set status asking a release
* to signal it, so it can safely park.
*/
return true;
if (ws > 0) { //waitStatus > 0,即是前趋节点的锁被取消的值(Node.CANCELLED,值是1)
/*
* Predecessor was cancelled. Skip over predecessors and
* indicate retry.
*/
do {
node.prev = pred = pred.prev; //修改当前节点的前趋节点,往前移一个节点。
} while (pred.waitStatus > 0);
pred.next = node;
} else {
/*
* waitStatus must be 0 or PROPAGATE. Indicate that we
* need a signal, but don't park yet. Caller will need to
* retry to make sure it cannot acquire before parking.
*/
compareAndSetWaitStatus(pred, ws, Node.SIGNAL); //前趋节点设置成需要唤醒的状态。
}
return false;
}
/**
* Convenience method to park and then check if interrupted
*
* @return {@code true} if interrupted
*/
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}
private static void selfInterrupt() {
Thread.currentThread().interrupt();
}
}
//==========================================================
一.公平锁FairSync
使用公平锁,创建ReentrantLock
ReentrantLock fairLock = new java.util.concurrent.locks.ReentrantLock(true);
fairLock.lock();
fairLock.unlock();
ReentrantLock.lock();==>>FairSync.lock()==>>AQS.acquire(1)实现:
1.!FairSync.tryAcquire(int acquires)//1为真,则表示没有获得锁,注意,前面有个"!"(非逻辑)
并且
2.AQS.acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
//Node.EXCLUSIVE就独占式锁,因为只有一个线程能获得锁,所以使用独占式锁;
//比如信号量Semaphore可以设置多个许可供给多个线程获得,则Semaphore会使用共享式锁Node.SHARED
(1和2)都为真 ==>>AQS.selfInterrupt()
//============================================================
FairSync.tryAcquire(int acquires)实现:
1.状态为0,则表示锁是空闲的
1.1 !AQS.hasQueuedPredecessors() //1.1为真,则表示等待队列里没有优先等待锁的线程节点
并且
1.2 AQS.compareAndSetState(0, 1) //使用CAS原子操作设置state值由0变为1
(1.1和1.2)都为真 ==>> 当前线程获得锁成功返回true。
2.状态不为0,则表示锁已被某个线程获得,
2.1判断锁的持有者是否当前线程
2.1.1是当前线程,则表示线程重复获得锁,将状态值state增加acquires,获得锁成功返回true。
2.1.2不是当前线程,尝试获得锁失败,返回false。
3. 返回false
//============================================================
总结:公平锁
线程请求获取锁时,判断状态state的值
1.当状态state为0时(即锁还没被线程占有),
1.1判断队列里有没前任优先线程节点,即,在当前线程之前有没其他线程在等待锁的释放
1.1.1如果没有优先线程,则当前线程可以获得锁
1.1.2如果有优先线程,则当前线程衔接在队尾阻塞等待锁空闲,等待其他线程唤醒来获得锁
2.当状态state不为0时,说明锁已经被某个线程占有,判断占有线程是否当前线程
2.1是当前线程,则线程可重复获得锁,将状态state值加1,表示线程又一次重复获得锁
2.2不是当前线程,则当前线程衔接在队尾阻塞等待锁空闲,等待其他线程唤醒来获得锁
//============================================================
总结:非公平锁
线程请求获取锁时,首先比其他线程优先获得锁(抢占式地,直接使用CAS(调用:compareAndSetState(0, 1))设置状态state值),
总之,如有刚好锁空闲时,非公平锁会优先获得锁,锁已被占有时,再衔接到队尾,排队等待锁。
不管是公平锁,还是非公平锁,没获得锁进入阻塞排队时,AQS都会使用CLH队列(对应到上面的acquireQueued方法),
当前线程会判断它的前趋节点,如果前趋节点的等待状态waitStatus是SIGNAL,则说明前趋节点也是在等待锁挂起中,那当前线程也会挂起等待锁;
如果前趋节点是队头head,则说明已经轮到当前线程获得锁;
释放锁时,会从队头的后继节点开始,唤醒挂起的后继节点,则后继获得锁。