AQSはどのように1つのInt値で読み書きの2つの状態を表します

2932 ワード

前回のブログではAQSのソースコード解析を更新しましたが、AQSはint値1つだけでスレッドブロックキューと実行メカニズムを実現できることがわかりました.
AQSに依存して実現されるロックには様々な種類があり、ReentrantLockはその一つである.次のブログでは、別のロックReentrantReadWriteLockを分析します.このロックは、書き込みロックと読み取りロックに関連する.一方,AQSは,int値1つだけでリードロックを区別している.ソースコードを簡単に理解するために、ここでまずこの知識点を説明します.
/*
 * Read vs write count extraction constants and functions.
 * Lock state is logically divided into two unsigned shorts:
 * The lower one representing the exclusive (writer) lock hold count,
 * and the upper the shared (reader) hold count.
 */

static final int SHARED_SHIFT   = 16;
static final int SHARED_UNIT    = (1 << SHARED_SHIFT);
static final int MAX_COUNT      = (1 << SHARED_SHIFT) - 1;
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;

/** Returns the number of shared holds represented in count  */
static int sharedCount(int c)    { return c >>> SHARED_SHIFT; }
/** Returns the number of exclusive holds represented in count  */
static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }

この部分のコードはAQSが1つのint値でリードロックとライトロックの2つの状態を表していることについて、実現原理を分析してみましょう
まず,intの値が32ビットであることを知っている.AQSはこの32ビットを高16ビットと低16ビットの2つの符号のないshort値に分けた.(ここでは記号のない数値について議論しますが、以下では強調しません).高さは16ビットがリードロック(共有ロック)を表し、低さは16ビットがライトロック(独占ロック)を表す
リードロック(共有ロック)
ライティングロック
0000000000000000
0000000000000000
最大共有数MAX_COUNTは1左シフト16桁減の1桁、つまりバイナリが1桁減の65536桁から65535桁減の10進数に変換された.同理最大独占数も65535であった.
では、AQSはどのようにしてリードロックの個数を取得しますか?sharedCount(int c)により,整数を符号なしに16ビット右にシフトし,リードロック数を得ることが分かった.具体的には、次の表の変換プロセスを参照してください.
1、現在リードロックがあるとする
リードロック(共有ロック)
                          
0000000000000001
0000000000000000
2、現在、リードロック個数を1つ加算(高さ16ビットはリードロックを表すため、毎回1つのリードロックが追加されると、現在の状態に65536が加算される)
リードロック(共有ロック)
 
0000000000000001
0000000000000000
0000000000000001
0000000000000000
0000000000000010
0000000000000000
 
3、現在リードロック個数を取得するには、符号なしで16ビット右シフトを行い、次のようなバイナリになる
リードロック(共有ロック)
 
0000000000000000
0000000000000010
このバイナリを10進数に変換すると10進数2になります.
これがリードロックの操作手順です.次に、書き込みロックがどのように操作されているかを見てみましょう.
1、現在書き込みロックがあるとする
ライティングロック
 
0000000000000000
0000000000000001
2、現在書き込みロックプラス1を行っています(16桁下は書き込みロックを表しているため、新たに書き込みロックを1つ追加するごとに、現在の状態に直接1を追加します)
ライティングロック
 
0000000000000000
0000000000000001
0000000000000000
0000000000000001
0000000000000000
0000000000000010
3、書き込みロックの個数を取得し、exclusiveCount(int c)法により、int cを上65535として書き込みロックの個数を得る
ライティングロック
 
0000000000000000
0000000000000010
0000000000000000
111111111111111111
0000000000000000
0000000000000010
読み取りロックと書き込みロックの操作手順が表示されます.ここから,AQSはリードロックとライトロックの扱い方が巧みで,常に上位16ビットを0にし,上位の影響を排除していることがわかる.ここはとても参考になるところです.
PS:このブログの内容は、次のReentrantReadWriteLockのソースコードを読むための知識の補足です.ReentrantReadWriteLockの内容が少し多いので、3~4つのブログに分けて分析するつもりです.お楽しみに...