ReentrantLockの実装原理の紹介(コード例)
この記事では、ReentrantLock の実装原理 (コード例) を紹介します。必要な方は参考にしてください。
並行プログラミングでは、synchronized キーワードに加えて、Java 並行性パッケージの java.util.concurrent.locks の ReentrantLock および ReentrantReadWriteLock も一般的に使用されるロック実装です。この記事では、リエントラント ロックの原理をソース コードから分析します。
まず、再入可能ロックについて説明します。スレッドはロックを取得した後、自身をブロックせずに複数回ロックを取得できます。
ReentrantLock は、抽象クラス AbstractQueuedSynchronizer (以下、AQS) に基づいて実装されます。
ソース コードを見てください:
まず、コンストラクターから、ReentrantLock には公平なロックと不公平なロックという 2 つのメカニズムがあることがわかります。
//默认非公平锁 public ReentrantLock() { sync = new NonfairSync(); } public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); }
まず、公平なロックと不公平なロックの違いを簡単に説明し、次に 2 つの異なる実装方法を分析します。
公平なロック: 複数のスレッドは先着順です。キューイングと同様に、後から来るスレッドはキューの最後に配置されます。
不公平なロック: ロックを奪い合います。掴まれていれば実行され、掴まれていなければブロックされます。ロックを取得したスレッドが解放されるまで待ってから、競争に参加してください。
したがって、通常は不公平なロックが使用されます。フェアロックよりも効率が高いです。
Get lock
Fair lock
final void lock() { acquire(1); } public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }
最初のステップは tryAcquire(arg) try ですFairSync によって実装された Lock を追加するための具体的なコードは次のとおりです:
protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { 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 で状態を取得します。 state が 0 の場合は、現時点でロックを取得しているスレッドがないことを意味します。
- if 判定では、まず AQS ノードのキューが空かどうかを判定します。空いていない場合は並ぶ必要があります。現時点ではロックは取得されていません。
- CAS アルゴリズムを使用して状態を 1 に更新してみます。更新が成功し、ロックが取得され、このときのスレッドが排他スレッド exclusiveOwnerThread に設定されます。 trueを返します。
- state が 0 でない場合は、スレッドがすでにロックを取得していることを意味します。したがって、ロックを取得したスレッド(排他スレッド)がカレントスレッドであるかどうかを判断する必要があります。
- 「はい」の場合、それは再入可能であることを意味します。状態を 1 増やします。 trueを返します。
- 最後のステップでは、ロックは取得されません。 false を返す;
- ロックの取得に失敗した場合は、まず addWaiter(Node.EXCLUSIVE) を実行し、現在のスレッドをキューに書き込みます。
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; }
新しいノードノードをカプセル化します
リンクされたリストの末尾が空かどうかを判断します。空でない場合は、新しいノード node' を最後まで書き込みます
'リンクされたリストの最後が空の場合は、enq(node) を使用して最後まで書き込みます。
キューに書き込んだ後、acquireQueued() メソッドは現在のスレッドを一時停止します。
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; } if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } finally { if (failed) cancelAcquire(node); } }
ループ内で、前のノードがヘッド ノードの場合は、再度ロックの取得を試みます。成功した場合、ループは終了し、 false が返されます。
は、前のノードの waitStatus に基づいて、現在のスレッドを実行する必要があるかどうかを判断します。一時停止中。 waitStatus は、ノードのキャンセル、ノードの待機などのノードのステータスを記録するために使用されます。
一時停止する必要があると判断した場合は、parkAndCheckInterrupt() メソッドを使用してスレッドを一時停止します。具体的には、LockSupport.park(this) を使用してスレッドを一時停止します。
最初のステップでロックの取得が成功した場合は、このノードのロック取得操作をキャンセルできます。
#不公平なロック
final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); } protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); }
- 更新に失敗した後、ロックを取得しようとしたとき
- ###公平なロックと比較すると、不公平なロックが発生します。 lock はロックの取得を試みます。キュー内に他のスレッドがあるかどうかを判断する必要はありません。
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; }
ログイン後にコピー
ロックを解放します
ロックを解放する手順は、公平なロックと不公平なロックの両方で同じです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; } //更新state 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; }
以上がReentrantLockの実装原理の紹介(コード例)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック











一部のアプリケーションが適切に機能しないようにする会社のセキュリティソフトウェアのトラブルシューティングとソリューション。多くの企業は、内部ネットワークセキュリティを確保するためにセキュリティソフトウェアを展開します。 ...

多くのアプリケーションシナリオでソートを実装するために名前を数値に変換するソリューションでは、ユーザーはグループ、特に1つでソートする必要がある場合があります...

システムドッキングでのフィールドマッピング処理は、システムドッキングを実行する際に難しい問題に遭遇することがよくあります。システムのインターフェイスフィールドを効果的にマッピングする方法A ...

データベース操作にMyBatis-Plusまたはその他のORMフレームワークを使用する場合、エンティティクラスの属性名に基づいてクエリ条件を構築する必要があることがよくあります。あなたが毎回手動で...

intellijideaultimatiateバージョンを使用してスプリングを開始します...

Javaオブジェクトと配列の変換:リスクの詳細な議論と鋳造タイプ変換の正しい方法多くのJava初心者は、オブジェクトのアレイへの変換に遭遇します...

eコマースプラットフォーム上のSKUおよびSPUテーブルの設計の詳細な説明この記事では、eコマースプラットフォームでのSKUとSPUのデータベース設計の問題、特にユーザー定義の販売を扱う方法について説明します。

Redisキャッシュソリューションは、製品ランキングリストの要件をどのように実現しますか?開発プロセス中に、多くの場合、ランキングの要件に対処する必要があります。
