【Java同時プログラミング実戦】–AQS(三):ブロック、起動:LockSupport


前回のブログ(「Java同時プログラミング実戦」–AQS(二):ロックの取得、ロックの解放)では、1つのスレッドがCLHキューに追加された場合、ヘッダノードでない場合は、ノードが停止する必要があるかどうかを判断する必要があると述べています.ロックを解除した後、スレッドの後続ノードを起動する必要があります.
ロックメソッド、acquireQueued()を呼び出します.
if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;

acquireQueued()でparkAndCheckInterrupt()を呼び出し、現在のスレッドを保留します.
private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this);
        return Thread.interrupted();
    }

LockSupportを呼び出します.park()メソッド.park()の場合:スレッドスケジューリングのために、ライセンスが使用可能になる前に現在のスレッドを無効にします.
ロックを解除すると、スレッドの次のノードを起動する必要があります.
public final boolean release(int arg) {
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

releaseメソッドでunparkSuccessor()を呼び出し、スレッドの後継ノードを起動します.unparkSuccessor()メソッドでLockSupport.unpark()で目覚めます.unpark():指定したスレッドのライセンスがまだ使用できない場合は、使用可能にします.

LockSupport


LockSupportは、ロックや他の同期クラスを作成するための基本スレッドブロック原語です.LockSupportを使用するスレッドごとに1つのライセンスが関連付けられます.このライセンスが使用可能で、プロセスで使用可能であれば、呼び出しpark()はすぐに返されます.そうしないとブロックされる可能性があります.ライセンスがまだ使用可能でない場合は、unparkを呼び出して使用可能にすることができる.ただし、ライセンスは再入力できません.つまり、park()メソッドを1回だけ呼び出すことができます.そうしないと、ブロックされ続けます.
LockSupport.park()、LockSupport.unpark()の役割は、スレッドのブロックとスレッドのブロック解除であり、park()とunpark()は「Thread.suspend()とThread.resumeによって発生する可能性のあるデッドロック」の問題に遭遇しない.もちろんパーク()、unpark()はペアで使用されます.
park():ライセンスが使用可能な場合は、ライセンスが使用され、呼び出しがすぐに返されます.それ以外の場合は、スレッドスケジュールの現在のスレッドを無効にし、次の3つのいずれかが発生する前にスリープ状態にします.
他のスレッドは、現在のスレッドをターゲットとしてunparkを呼び出す.または他のスレッドが現在のスレッドを中断します.またはこの呼び出しは論理的に(すなわち理由もなく)返される.そのソースコードは、
public static void park() {
        unsafe.park(false, 0L);
    }
unpark:指定されたスレッドのライセンスがまだ使用できない場合に使用可能にする.スレッドがpark上でブロックされている場合、そのブロック状態は解除されます.そうでなければ、次の呼び出しparkがブロックされないことを保証します.指定したスレッドがまだ起動していない場合は、この操作の効果は保証されません.ソースコードは次のとおりです.
public static void unpark(Thread thread) {
        if (thread != null) { 
            Object lock = unsafe.getObject(thread, lockOffset);
            synchronized (lock) { 
                if (thread.isAlive()) { 
                    unsafe.unpark(thread); 
                } 
            } 
        } 
    }
では、一般的にpark()とunpark()がペアで表示されます.また、unparkはparkの実行後に実行する必要があります.もちろん、unparkスレッドを呼び出さないとブロックされるわけではありません.parkにはタイムスタンプ(parkNanos(long nanos):スレッドスケジューリングのために現在のスレッドを無効にし、許可が使用可能でない限り、指定された待機時間を待つ方法があります.参考資料1、LockSupportのparkとunparkの基本的な使用、およびスレッド中断に対する応答性