JAva非公平ロック

5958 ワード

非公開ロックの取得(JDK 1.7.0_40ベース)
非公平ロックと公平ロックはロックを取得する方法で、流れは同じです.それらの違いは主に「ロックを取得しようとするメカニズムが異なる」ことに表れている.簡単に言えば、「フェアロック」は、ロックを取得しようとするたびに、フェアポリシーを採用します(待機キューに基づいて順番に待機をソートします).一方、非フェアロックは、ロックを取得しようとするたびに非フェアポリシーを採用します(待機キューを無視してロックを直接取得しようとしますが、ロックがアイドルであればステータスを取得できます.ロックを取得します).前述の「Javaマルチスレッドシリーズ-「JUCロック」03のフェアロック(一)」では、フェアロックを取得するプロセスとメカニズムについて詳しく説明しました.次に,コード解析により以下の非公平ロックを取得するプロセスを示す.
1. lock()
ロック()はReentrantLock.JAvaのNonfairSyncクラスでは、次のようにソースコードが実装されています.
final void lock() {
    if (compareAndSetState(0, 1))
        setExclusiveOwnerThread(Thread.currentThread());
    else
        acquire(1);
}

説明:lock()は、まずcompareAndSet(0,1)によって「ロック」がアイドル状態かどうかを判断します.はい、「現在のスレッド」は直接「ロック」を取得します.そうでなければacquire(1)を呼び出してロックを取得する.(01)compareAndSetState()はCAS関数であり、現在のロックの状態を比較して設定する役割を果たす.ロックのステータス値が0の場合、ロックのステータス値を1に設定します.(02)setExclusiveOwnerThread(Thread.currentThread()の役割は、「現在のスレッド」を「ロック」の所有者に設定することです.
「フェアロック」と「非フェアロック」lock()の対比について
      --     lock()  ,     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)そして、acquireQueued()を呼び出してロックを取得する.acquireQued()では、現在のスレッドは、「CLHキュー」の前のすべてのスレッドがロックを実行して解放した後、ロックを取得して戻るのを待っています.現在のスレッドがスリープ待機中に中断された場合、selfInterrupt()を呼び出して自分で中断を生成します.
「フェアロック」と「非フェアロック」acquire()の対比について
tryAcquire()       ;             。        “              ”!
 “Java     --“JUC ”03     ( )” ,       acquire()tryAcquire()

非公正ロックのtryAcquire()はReentrantLock.JAvaのNonfairSyncクラスで実装され、ソースコードは以下の通りです.
protected final boolean tryAcquire(int acquires) {
    return nonfairTryAcquire(acquires);
}

NonfairTryAcquire()ReentrantLock.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つの場合を用いないと、試行に失敗すると考えられる.
「フェアロック」と「非フェアロック」tryAcquire()の比較について
        ,            。
          ,  “ ”          ,          CLH       ;   ,    。
            ,  “ ”         ,     CLH     ,       。

非フェアロックの解放(JDK 1.7.0_40ベース)
非公平ロックと公平ロックはロックを解放する方法と策略で同じである.前述の「Javaマルチスレッドシリーズ-「JUCロック」04のフェアロック(二)」では、「フェアロックの解放」について紹介した.ここではこれ以上説明を繰り返さない.
公平ロックと非公平ロックの違いをまとめると,ロックを取得するメカニズムの違いである.現在のスレッドがCLH待ちキューのヘッダである場合にのみロックが取得される.フェアロックではなく、現在のロックがアイドル状態であれば、CLH待ちキュー内の順序にかかわらず、ロックを直接取得します.非フェアロックがロックの取得に失敗した場合にのみ、フェアロックのようにCLH待ちキューソート待ちに入ります.
転載先:http://www.cnblogs.com/skywang12345/p/3496651.html