ホームページ Java &#&チュートリアル JAVA の ReadWriteLock インターフェイスとその実装 ReentrantReadWriteLock メソッド

JAVA の ReadWriteLock インターフェイスとその実装 ReentrantReadWriteLock メソッド

Jun 30, 2017 am 10:32 AM
java readwritelock 成し遂げる

次のエディターは、R​​eadWriteLock インターフェイスとその実装 ReentrantReadWriteLock メソッドに関する記事を提供します。編集者はこれがとても良いものだと思ったので、皆さんの参考として今から共有します。エディターに従って見てみましょう

Java 同時実行パッケージのロック パッケージのロックが基本的に導入されました。シンクロナイザー AQS の動作メカニズムを明確に理解すると、実際には非常に簡単になります。この章では、もう 1 つの重要なロックである ReentrantReadWriteLock 読み取り/書き込みロックに焦点を当てます。

ReentrantLock は排他的ロックです。これは、ロックを 1 つのスレッドによってのみ取得できることを意味します。しかし、スレッドが読み取り操作のみを実行するシナリオの場合はどうなるでしょうか。このように、ReentrantLock は、読み取りスレッドのセキュリティを確保する必要がなく、この方法でのみパフォーマンスと効率を最大限に保証できます。 ReentrantReadWriteLock は、読み取りロックと書き込みロックに分割されており、書き込みロックを取得できるのは 1 つの書き込み操作スレッドだけです。 lock は共有ロック (AQS の共有モード)、読み取りロックは排他ロック (AQS の排他モード) です。まず、読み取り/書き込みロックのインターフェイス クラスを見てみましょう:

ReadWriteLock インターフェイスには、読み取りロックを取得するメソッドと書き込みロックを取得するメソッドの 2 つのメソッドのみが定義されていることがわかります。以下はReadWriteLock - ReentrantReadWriteLockの実装クラスです。

ReentrantLock と同様に、ReentrantReadWriteLock も内部クラス Sync を通じてシンクロナイザー AQS を実装します。この点の考え方は ReentrantLock と似ています。 ReadWriteLock インターフェイスで取得される読み取りロックと書き込みロックはどのように実装されますか?

//ReentrantReadWriteLock
private final ReentrantReadWriteLock.ReadLock readerLock;
private final ReentrantReadWriteLock.WriteLock writerLock;
final Sync sync;
public ReentrantReadWriteLock(){
 this(false); //默认非公平锁
}
public ReentrantReadWriteLock(boolean fair) {
 sync = fair ? new FairSync() : new NonfairSync(); //锁类型(公平/非公平)
 readerLock = new ReadLock(this); //构造读锁
 writerLock = new WriteLock(this); //构造写锁
}
……
public ReentrantReadWriteLock.WriteLock writeLock0{return writerLock;}
public ReentrantReadWriteLock.ReadLock readLock0{return ReaderLock;}
ログイン後にコピー
//ReentrantReadWriteLock$ReadLock
public static class ReadLock implements Lock {
 protected ReadLock(ReentrantReadwritLock lock) {
  sync = lock.sync;  //最后还是通过Sync内部类实现锁
  }
 …… //它实现的是Lock接口,其余的实现可以和ReentrantLock作对比,获取锁、释放锁等等
}
ログイン後にコピー
//ReentrantReadWriteLock$WriteLock
public static class WriteLock implemnts Lock {
 protected WriteLock(ReentrantReadWriteLock lock) {
  sync = lock.sync;
  }
…… //它实现的是Lock接口,其余的实现可以和ReentrantLock作对比,获取锁、释放锁等等
}
ログイン後にコピー


上記は ReentrantReadWriteLock の概要です。実際には、その中に ReadLock と WriteLock という 2 つのロックがあることがわかります。これは、セルフロック インターフェイスを実装しており、ReentrantLock と比較できます。これら 2 つのロックの内部実装は、シンクロナイザー AQS である Sync を通じて実装されます。これは、ReentrantLock の Sync と比較することもできます。

AQS を振り返ると、その内部には 2 つの重要なデータ構造があります。1 つは同期

キュー
で、もう 1 つは同期 ステータス です。この同期ステータスは、読み取り/書き込みステータスである読み取り/書き込みロックに適用されます。ただし、AQS では、同期ステータスを表す状態整数のみが存在します。読み取り/書き込みロックでは、記録する必要がある読み取りと書き込みの 2 つの同期ステータスがあります。したがって、読み取り/書き込みロックは AQS で状態整数を処理します。これは合計 4 バイトと 32 ビットの int 変数であり、読み取り状態と書き込み状態はそれぞれ 16 ビットを占有します。上位 16 ビットは読み取りを表します。 16 ビットは書き込みを示します。

ここで質問があります。state の値が 5 の場合、バイナリは (00000000000000000000000000000101) になります。これには、変位操作を使用する必要があります。計算方法は、書き込み状態 state & 0x0000FFFF、読み取り状態 state >>> 16 です。書き込み状態を 1 増やすことは状態 + 1 に等しく、読み取り状態を 1 増やすことは状態 + (1 < < 16) に等しくなります。ビットシフト演算

については、『

<<、>>、>>>シフト演算』を参照してください。 書き込みロックの取得と解放

これまでの経験に基づいて、AQS はロックを取得するためのアルゴリズム スケルトンをすでに設定しており、tryAcquire (排他的ロック) を実装するためにサブクラスのみが必要であることがわかります。 tryAcquire を確認します。

//ReentrantReadWriteLock$Sync
protected final boolean tryAcquire(int acquires) {
 Thread current = Thread.currentThread;
 int c = getState(); //获取state状态
 int w = exclusiveCount(c); //获取写状态,即 state & 0x00001111
 if (c != 0) { //存在同步状态(读或写),作下一步判断
  if (w == 0 || current != getExclusiveOwnerThread())  //写状态为0,但同步状态不为0表示有读状态,此时获取锁失败,或者当前已经有其他写线程获取了锁此时也获取锁失败
   return false;
  if (w + exclusiveCount(acquire) > MAX_COUNT) //锁重入是否超过限制
   throw new Error(“Maxium lock count exceeded”);
  setState(c + acquire); //记录锁状态
  return true;
  }
  if (writerShouldBlock() || !compareAndSetState(c, c + acquires))
   return false;  //writerShouldBlock对于非公平锁总是返回false,对于公平锁则判断同步队列中是否有前驱节点
  setExclusiveOwnerThread(current);
  return true;
}
ログイン後にコピー

上記は書き込みロックのステータス取得です。わかりにくいのは、このメソッドは上記で説明したとおり、Unfair ロックの場合は false を返しますが、Fair ロックの場合は次のように hasQueuedPredecessors メソッドが呼び出されます。
 //ReentrantReadWriteLock$FairSync
 final boolean writerShouldBlock() {
  return hasQueuedPredecessors();
 }
ログイン後にコピー

理由はなぜですか?これは、不公平なロックと公正なロックの違いに戻ります。詳細については、「5. ロック インターフェイスとその実装 ReentrantLock」を参照してください。不公平なロックの場合、スレッドはロックを取得するたびに、同期キューにスレッドがあるかどうかに関係なく、まずロックの取得操作を強制します。取得できない場合、スレッドはキューの最後まで構築されます。同期キューが存在する限り、公平なロックの場合。キュー内にスレッドがある場合、ロックは取得されませんが、スレッド構造はキューの最後に追加されます。書き込みステータスの取得に戻ります。tryAcquire メソッドでは、ロックを保持しているスレッドがないことがわかりましたが、この時点では、不公平なロックの場合はロックの取得、公正なロックの場合は、対応する操作が異なるロックに従って実行されます。 - 同期キュー スレッド内にスレッドがあり、ロックの取得がなく、キューの最後に追加されます。

書き込みロックの解放プロセスは、基本的に ReentrantLock の解放プロセスと似ています。結局のところ、これらはすべて排他ロックであり、書き込みロックが完全に解放されたことを意味する 0 になるまで、書き込みステータスが減少します。

リードロックの取得と解除

同様に、これまでの経験に基づいて、AQS はロックを取得するためのアルゴリズム スケルトンをすでに設定しており、サブクラスで tryAcquireShared (共有ロック) を実装するだけで十分であることがわかります。そのため、tryAcquireShared を確認するだけで済みます。共有モードのロックでは、複数のスレッドが同時にロックを取得できることがわかっています。ここで、T1 スレッドがロックを取得し、このとき、T2 も同期状態を取得します。 lock、state=2、次に T1 スレッド Re-entry state = 3。これは、読み取り状態がすべてのスレッドの読み取りロック数と、各スレッドが読み取りロックを取得した回数の合計であることを意味します。 ThreadLock にのみ保存され、スレッド自体によって維持されるため、ここでいくつかの複雑な処理を実行する必要があり、ソース コードは少し長くなりますが、複雑なのは各スレッドが取得する回数を保存するという事実にあります。詳細については、ソース コードの tryAcquireShared を参照して、上記の書き込みロックの取得の分析と組み合わせて理解することは難しくありません。

読み取りロックの解放で注目すべき点は、それ自体が維持するロック取得の数と、シフト操作による状態の減少です (1

以上がJAVA の ReadWriteLock インターフェイスとその実装 ReentrantReadWriteLock メソッドの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

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

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

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

Javaの完全数 Javaの完全数 Aug 30, 2024 pm 04:28 PM

Java における完全数のガイド。ここでは、定義、Java で完全数を確認する方法、コード実装の例について説明します。

Java の乱数ジェネレーター Java の乱数ジェネレーター Aug 30, 2024 pm 04:27 PM

Java の乱数ジェネレーターのガイド。ここでは、Java の関数について例を挙げて説明し、2 つの異なるジェネレーターについて例を挙げて説明します。

ジャワのウェカ ジャワのウェカ Aug 30, 2024 pm 04:28 PM

Java の Weka へのガイド。ここでは、weka java の概要、使い方、プラットフォームの種類、利点について例を交えて説明します。

Javaのスミス番号 Javaのスミス番号 Aug 30, 2024 pm 04:28 PM

Java のスミス番号のガイド。ここでは定義、Java でスミス番号を確認する方法について説明します。コード実装の例。

Java Springのインタビューの質問 Java Springのインタビューの質問 Aug 30, 2024 pm 04:29 PM

この記事では、Java Spring の面接で最もよく聞かれる質問とその詳細な回答をまとめました。面接を突破できるように。

Java 8 Stream Foreachから休憩または戻ってきますか? Java 8 Stream Foreachから休憩または戻ってきますか? Feb 07, 2025 pm 12:09 PM

Java 8は、Stream APIを導入し、データ収集を処理する強力で表現力のある方法を提供します。ただし、ストリームを使用する際の一般的な質問は次のとおりです。 従来のループにより、早期の中断やリターンが可能になりますが、StreamのForeachメソッドはこの方法を直接サポートしていません。この記事では、理由を説明し、ストリーム処理システムに早期終了を実装するための代替方法を調査します。 さらに読み取り:JavaストリームAPIの改善 ストリームを理解してください Foreachメソッドは、ストリーム内の各要素で1つの操作を実行する端末操作です。その設計意図はです

Java での日付までのタイムスタンプ Java での日付までのタイムスタンプ Aug 30, 2024 pm 04:28 PM

Java での日付までのタイムスタンプに関するガイド。ここでは、Java でタイムスタンプを日付に変換する方法とその概要について、例とともに説明します。

カプセルの量を見つけるためのJavaプログラム カプセルの量を見つけるためのJavaプログラム Feb 07, 2025 am 11:37 AM

カプセルは3次元の幾何学的図形で、両端にシリンダーと半球で構成されています。カプセルの体積は、シリンダーの体積と両端に半球の体積を追加することで計算できます。このチュートリアルでは、さまざまな方法を使用して、Javaの特定のカプセルの体積を計算する方法について説明します。 カプセルボリュームフォーミュラ カプセルボリュームの式は次のとおりです。 カプセル体積=円筒形の体積2つの半球体積 で、 R:半球の半径。 H:シリンダーの高さ(半球を除く)。 例1 入力 RADIUS = 5ユニット 高さ= 10単位 出力 ボリューム= 1570.8立方ユニット 説明する 式を使用してボリュームを計算します。 ボリューム=π×R2×H(4

See all articles