同時8:ReentrantLock実装分析

3576 ワード

明示的ロック


synchronizedは内蔵ロックと呼ばれ、スレッドは臨界領域に入ると自動的にロックを取得し、同期コードを実行すると自動的にロックを解放します.J.U.CのReentrantLock、ReentrantReadWriteLockは、synchronizedに呼応して通常明示的なロックと呼ばれる手動でロックおよびロック解除を行う必要があります.

ReentrantLock


名前の通り再読み込みがサポートされ、synchronizedと同様にスレッドは同じロックを繰り返し取得できます.同時にReentrantLockは公平性設定をサポートし、公平ロックまたは非公平ロックに設定することができます.
public class ReentrantLock implements Lock, java.io.Serializable {
    /**   AQS  */
    abstract static class Sync extends AbstractQueuedSynhronizer {... ...}  
    /**   */
    static final class NonfairSync extends Sync{... ...}
    /**   */
    static final class FairSync extends Sync{... ...}
    /**   */
    private final Sync sync;
    /**   */
    public ReentrantLock() {
        sync = new NonfairSync();
    }
    /**   */
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }
    ... ...
}

ReentrantLockはキュー同期器AQSをベース同期ツールとして使用し、NonfairSyncは非公平ロック、FairSyncは公平ロック同期器、デフォルトは非公平ロック、fairで公平ロックに設定できます.
非公開ロック:
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;//  +1
        if (nextc < 0) // overflow
        throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
    }
    return false;
}

s 1:State=0は最初のロックで、CASは同期状態を1に設定し、設定成功説明はロックに取得し、ロックを持つスレッドを現在のスレッドに設定し、返します.s 2:State>0であり、保有スレッドが現在のスレッドであり、StateをState+1に設定する.ここではスレッド競合は存在しないので、直接設定すればよい.
フェアロックのロック方法:
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;//  +1
    if (nextc < 0)
        throw new Error("Maximum lock count exceeded");
    setState(nextc);
    return true;
    }
    return false;
}

hasQueuedPredecessors()メソッドは、AQS同期キューに待機するノードがあるか否かを判断し、ある場合は取得ロックを放棄する.ここでは公平ロックFIFO特性を体現する場所であり、最も待機しているノードに優先的にロックを取得させる.
ロック解除方法:
protected final boolean tryRelease(int releases) {
    int c = getState() - releases;// -1
    // 
    if (Thread.currentThread() != getExclusiveOwnerThread())
    throw new IllegalMonitorStateException();
    boolean free = false;
    if (c == 0) { //   
    free = true;
    setExclusiveOwnerThread(null);
    }
    setState(c);//  
    return free;
}

非フェアロックとフェアロックの解放は、親SyncのtryReleaseメソッドを呼び出します.ロックが完全に解放された場合、すなわちc==0であると、同期キューで待機している後続ノードが起動し、ロックが完全に解放されていない場合、後続ノードは起動しません.ロックを再ロックするには、ロックを何回か追加すると、同じ回数のロックを解除する必要があります.

小結


1:synchronized暗黙的なロック解除、ReentrantLock手動のロック解除が必要2:同期コードに異常が発生した場合、synchronizedは自動的にロックを解除し、ReentrantLockはfinallyで解放する必要があります.3:ReentrantLock非ブロック取得ロック(tryLock)、synchronizedはできません.4:ReentrantLockは割り込み(lockInterruptibly)に応答でき、synchronizedはできません.5:ReentrantLockはタイムアウトメカニズム(tryLock(timeout,unit))を持っていて、synchronizedはできません.6:ReentrantLockはフェアロックと非パブリックロックの選択をサポートしますが、synchronizedは非フェアロックのみです.
コードワードは容易ではありませんて、転載して原文の接続を保留してくださいhttps://www.jianshu.com/p/79cbb3ab8af2