先ほどアンフェアロックの取得についてお話しましたが、フェアロックについては触れませんでしたが、実際、フェアロックとアンフェアロックの違いはプリエンプションの問題です。フェアロックの場合、プリエンプションロック操作は発生しません。 、しかし最初の裁判官、コードを見てください
if (c == 0) {
if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
追加のメソッドhasQueuedPredecessorsがあります。これは、ブロックされたキューに待機中のスレッドがあるかどうかを確認することを意味します。ある場合は、待機してプリエンプションしないでください。ない場合は、直接プリエンプションし、非フェアロックが直接先行します。これがフェアロックとアンフェアロックの違いは他の場所でもほぼ同じなのであまりありません。
ロックの解除について話しましょうもちろん、フェアロックとアンフェアロックのロックを解除する方法は同じです。話を始めましょう、コードに行きましょう!
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;
}
これは、ReentrantLockがロックを解放するコードです。少し見てみましょう。張トゥハを表示
実際、ReentrantLockでのフェアロックリリースロックの実現を見てください。
protected final boolean tryRelease(int releases) { //releases 目前是1,这个说下哈
//获取线程的状态,并减一,赋值给新的状态c
int c = getState() - releases;
//判断当前线程,如果不是锁的持有者,那你还释放啥?直接报错
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false; //定义一个字段,表示释放锁成功
if (c == 0) { //状态status恢复成0.就是没有线程持有锁了,释放成功
free = true;
//设置锁的持有者为空
setExclusiveOwnerThread(null);
}
setState(c); //state 重新复赋值
return free;
}
次に、待機中のスレッドを解放し、ロックガンドリル操作を実行します。
private void unparkSuccessor(Node node) { //注意,传进来的是头结点
//获取阻塞队列节点的waitStatus,无异常的话应该是-1,插入尾部的时候都把前置节点改成了-1
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0); // 修改状态,cas 头结点
//获取下一个节点,也就是要释放的节点
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);
}
これが主な説明であり、一部は説明されていない可能性がありますが、ReentrantLockの理解には影響しません。もちろん、コードを見るのも少しめまいがするかもしれません。以下に示す2つのスケッチはうまく描かれていません。許してください。
他の絵はまだ描かれていて、後で追加されるでしょう。
このロック(不公平なロック)の処理を要約すると、最初に、CAS楽観的ロックロックが失敗すると、ブロッキングキューに入ります。ブロッキングキューが空の場合、ブロッキングキューが初期化され、現在のスレッドが最後に追加されます。ブロッキングキューの。
現在のノードのフロントノードを決定します。ヘッドノードの場合は、直接リソースを取得します。ヘッドノードは空であるため、操作の便宜のために追加されます。現在のノードのフロントノードwaitStatusが1の場合、このノードを削除し、現在のノードの前のノードが-1に設定されるまでループします。その後、現在のスレッドを中断できます。これがメインのロックプロセスです。
気分が良ければ気に入ってください〜
犠牲も勝利もありません〜