AQSソースコード分析
AQS(AbstractQueueedSynchronizer)作業キューリソース取得完了するためにメンバ変数INTが内蔵FIFOキューを介して、同期状態を表す使用
voaltile状態が視認性を確保することで、状態変数スレッド
AQS状態のメソッドを変更は、三次のとおりであります
getState()
setState()
compareAndSetState()
CASを使用してノードをキューに追加する利点は
、リンクリスト全体をロックせずにノードを追加できることです
lock()メソッド専用
最初の呼び出し同期の取得メソッド
public void lock() {
sync.acquire(1);
}
AQSに入り、acqurie()メソッドを呼び出す
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
最初のブランチはtryAcquire()を実行し、
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
内部をクリックした後、私はnonfairTryAcquire()を見つけました
/**
*尝试获取锁,成功返回true,失败返回false
**/
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
//获取当前的标志的状态
int c = getState();
//c==0表示没人获取这把锁
if (c == 0) {
//使用CAS操作尝试获取这把锁
if (compareAndSetState(0, acquires)) {
//如果获取成功,设置为独占线程
setExclusiveOwnerThread(current);
return true;
}
}
//如果该线程已经占有了该锁,将标志位加1,这就是可重入的原理
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;
}
tryAccquire()がfalseを返す場合は、acquireQueued(addWaiter(Node.EXCLUSIVE)、arg)ブランチに入ります。
最初に、addWaiter()のソースコードを確認します。
private Node addWaiter(Node mode) {
//创建一个新的节点
Node node = new Node(mode);
//for是个死循环,不达目的不罢休
for (;;) {
//tail是等待队列的尾巴节点
Node oldTail = tail;
if (oldTail != null) {
//尾部节点不为空,用setPrevRelaxed()函数设置
//node的上一节点
node.setPrevRelaxed(oldTail);
//通过CAS操作加入等待队列
if (compareAndSetTail(oldTail, node)) {
oldTail.next = node;
return node;
}
} else {
initializeSyncQueue();
}
}
}
//初始化等待队列
private final void initializeSyncQueue() {
Node h;
if (HEAD.compareAndSet(this, null, (h = new Node())))
tail = h;
}
以下のacquireQueuedメソッドをご覧ください
final boolean acquireQueued(final Node node, int arg) {
boolean interrupted = false;
try {
//死循环
for (;;) {
//p为node的前驱
final Node p = node.predecessor();
//如果p为头节点,tryAcquire成功
if (p == head && tryAcquire(arg)) {
//设置node为头节点,也就是获取锁
setHead(node);
p.next = null; // help GC
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node))
interrupted |= parkAndCheckInterrupt();
}
} catch (Throwable t) {
cancelAcquire(node);
if (interrupted)
selfInterrupt();
throw t;
}
}
/**
* 如果尝试获取锁失败,检查并更新节点状态.
* 如果节点线程被block住就返回true
*
*
* @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)
/*
* This node has already set status asking a release
* to signal it, so it can safely park.
*
*/
return true;
if (ws > 0) {
/*
* Predecessor was cancelled. Skip over predecessors and
* indicate retry.
* 大于0跳过节点
*/
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.
*/
pred.compareAndSetWaitStatus(ws, Node.SIGNAL);
}
return false;
}
waitStatusは主に次のステータスを持っています
static final Node EXCLUSIVE = null;
/** waitStatus value to indicate thread has cancelled. */
static final int CANCELLED = 1;
/** waitStatus value to indicate successor's thread needs unparking. 后继unpark*/
static final int SIGNAL = -1;
/** waitStatus value to indicate thread is waiting on condition. condition队列*/
static final int CONDITION = -2;
/**
* waitStatus value to indicate the next acquireShared should
* unconditionally propagate.
*/
static final int PROPAGATE = -3;
シグナル
このノードの後続ノードは(パークにより)ブロックされる(または間もなくブロックされる)ため、現在のノードは、解放またはキャンセルするときに後続ノードのパークを解除する必要があります。競合を回避するには、取得メソッドは最初にシグナルが必要であることを示し、アトミック取得を再試行する必要があります、そして失敗した場合、ブロックします。
現在のノードがリソースを解放またはキャンセルするとき、現在のノードはunpark()後続ノードである必要があります
unLock()排他
リリースを入力してください
public void unlock() {
sync.release(1);
}
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()
//当c=0,释放资源
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;
}
読み書きロック
main(){
ReentrantReadWriteLock reentrantLock = new ReentrantReadWriteLock();
reentrantLock.readLock().lock();
}
sync.acqurireShared()を呼び出す
public void lock() {
sync.acquireShared(1);
}
テンプレートメソッドを呼び出す
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
tryAcquireShared(INT引数)この方法は、int型の値を返し、戻り値が0以上である場合、同期状態を取得することができる
doAcquireShared()待機キューに追加します
フラグビットは32ビットです。
読み取り状態は上位16ビットで、書き込み状態は下位16ビットです。
書き込み状態= state&0x0000FFFF
読み取り状態= state>>>16
書き込み状態+ 1 =状態+ 1
読み取り状態+ 1 = state+(1<<<16)
状態> 0のstate&0x0000FFFF=0,state>>>16 > 0
場合、読み取りロックは
状態> 0を取得しstate&0x0000FFFF>0,state>>>16 >=0
、書き込みロック取得 `
ダウングレードをロック
ロックのダウングレードとは、書き込みロックを読み取りロックにダウングレードすることです。現在のスレッドが書き込みロックを所有し、それを解放し、最後に読み取りロックを取得する場合、このセグメンテーション完了のプロセスをロック降格と呼ぶことはできません。ロックダウングレードとは、(現在所有されている)書き込みロックを保持し、読み取りロックを取得して、(以前に所有されていた)書き込みロックを解放するプロセスのことです。