Java concurrencyの非公平ロック動力ノードJava学院の整理


非公平ロックを取得する(JDK 1.7.0_に基づく。40)
非公平ロックと公平ロックはロックを獲得する方法で流れは同じです。それらの違いは主に「ロックを取得しようとする試みのメカニズムが異なる」ということである。簡単に言えば、「公平錠」はロックを獲得しようとするたびに公平な策略を採用します。一方、「アンフェアロック」は、ロックを取得しようとするたびに、非公正なポリシーを採用しています。(待ち行列を無視して、直接にロックを取得しようとしています。アイドル状態であれば、ロックを取得することができます。)。 
1.ロック()

lock() ReentrantLock.java NonfairSync    ,      :
final void lock() {
  if (compareAndSetState(0, 1))
    setExclusiveOwnerThread(Thread.currentThread());
  else
    acquire(1);
}
説明:
ロック()はまず、compreAndSet(0,1)で「ロック」が空き状態かどうかを判断します。はい、「現在スレッド」は直接に「ロック」を取得します。そうでない場合は、acquire(1)を呼び出してロックを取得します。
(01)compreAndSetState()はCAS関数で、現在のロック状態を比較して設定する役割をしています。ロックの状態値が0なら、ロックの状態値を1とします。
(02)setExclusive OwnerantThread(Thread.current Thread)の役割は、「現在スレッド」を「ロック」の所有者に設定することです。
「公平ロック」と「非公平ロック」のロックに関する対比
  • 公平ロック   -- 公平ロックのロック関数は、直接acquire(1)を呼び出します。
  • は、非公平ロックです。現在ロックされている状態が空いているかどうかを先に判断します。
  • 2.acquire()
    acquire()はAQSで実現されました。ソースは以下の通りです。
    
    public final void acquire(int arg) {
      if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
    }
    (01)「現在スレッド」は、まずtryAcquire()を介してロックを取得する試みです。成功したら、直接に戻ります。試行に失敗したら、待ち行列に入って順番に並び、鍵を取得します。
    (02)「現在スレッド」の試みが失敗した場合は、先にaddWaiter(Node.EXCLUSIVE)を通じて、「現在スレッド」を「CLHキュー(ブロックされていないFIFOキュー)」の末尾に追加します。
    (03)その後、アクアQueued()を呼び出してロックを取得します。acquire Queueued()では、現在のスレッドは、「CLHキュー」の前にあるすべてのスレッドが実行され、ロックが解除された後、ロックが取得されて戻ります。「現在のスレッド」が休止待ち中に中断された場合、self Interrupt()を呼び出して、自分で中断を発生させます。
    「公平ロック」と「非公平ロック」の対比
    公正ロックと非公平ロックは、tryAcquire()関数の実装だけが異なる。つまり、ロックを取得しようとする仕組みが違っています。これは私達が言っている「ロック戦略の違いを得るところ」です。
    非公正ロックのtryAcquire()はRentrant Lock.javaのNonfairSync類で実現され、ソースは以下の通りです。
    
    protected final boolean tryAcquire(int acquires) {
      return nonfairTryAcquire(acquires);
    }
    
    nonfairTryAcquire()はRentrant Lock.javaのSync類で実現されています。ソースは以下の通りです。
    
    final boolean nonfairTryAcquire(int acquires) {
      //   “    ”
      final Thread current = Thread.currentThread();
      //   “ ”   
      int c = getState();
      // c=0   “           ”
      if (c == 0) {
        //  “           ”,   CAS    “ ”    acquires。
        //   ,  “    ”      。
        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;
    }
    
    
    説明:
    コードによって、tryAcquire()の役割はロックを取得することを試みることであると分析できます。
    (01)「錠」がスレッドによって所有されていない場合、CAS関数で「ロック」を設定した状態はacquiresであり、同時に「現在のスレッド」をロックの所有者として設定し、trueに戻る。
    (02)「錠」の持ち主が現在のスレッドである場合は、ロックの状態を更新すれば良いです。
    (03)用語の上の2つの場合でなければ、試みは失敗したと考える。
    「公平ロック」と「非公平ロック」の対比
    公正ロックと非公平ロックは、ロックを獲得する方法が違っています。
    公平ロックがロックを取得しようとすると、「ロック」がスレッドによってロックされていなくても、自分がCLH待ちの列の先頭かどうかを判断します。はい、鍵をもらいます。
    アンフェアロックではなく、ロックを取得しようとすると、「ロック」がスレッドによって保持されていない場合、CLHキューのどこにあるかに関わらず、直接にロックを取得する。
    アンフェアロックを解除します。40)
    非公平ロックと公平ロックは解除ロックの方法と策略において同じです。
    締め括りをつける
    公平錠と非公平錠の違いは、鍵を得る仕組みの違いです。現在のスレッドがCLH待ちの列のヘッダであるときのみ、ロックを取得することができる。公正ロックではなく、現在のロックがアイドル状態である限り、直接にロックを取得し、CLHがキューの順序を待つことなく。
    非公平ロックがロックを取得しようとしたときにのみ、公平ロックのようにCLHに入って待ち行列が並びます。