Javaの同時実行性:スレッドの一時停止とウェイクアップLockSupportツールクラスの詳細

LockSupportの概要

LockSupportツールクラスは、最も基本的なスレッドブロックおよびウェイクアップ関数を提供する一連のパブリック静的メソッド定義ます。これは、ロックおよびその他の同期クラスを作成するための基礎です。スレッドをブロックし、スレッドをウェイクアップする場所があります。 AQSは、LockSupportを使用します。次の段落のように、提供されているパークメソッドとパーク解除メソッド。

// 挂起线程
	private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this);
        return Thread.interrupted();
    }
	// 唤醒线程
    private void unparkSuccessor(Node node) {
		//...
        if (s != null)
            LockSupport.unpark(s.thread);
    }

パークおよびアンパーク関連のメソッド

LockSupportは、現在のスレッドをブロックするために、parkで始まる一連のメソッドを提供します[静的な省略]:

void park():現在のスレッドをブロックします。unpark(Threadthread)メソッドが呼び出された場合、または現在のスレッドが中断された場合、park()メソッドから戻ることができます。

void parkNanos(long nanos):現在のスレッドをナノ秒ナノ秒以内でブロックします。return条件は、park()に基づいてタイムアウトリターンを追加します。

void parkUntil(long deadline):締め切り[1970年から締め切りまでのミリ秒数]の時間まで現在のスレッドをブロックします。

void unpark(Thread thread):ブロックされた状態でスレッドスレッドをウェイクアップします。

JDK1.6では、ブロッカーパラメータを使用するいくつかのメソッドが追加されました。ブロッカーパラメータは、現在のスレッドがトラブルシューティングとシステム監視を待機しているオブジェクトを識別するために使用されます。

以下に、park()メソッドとunpark()メソッドの使用法を示します。

スレッドスレッドでpark()メソッドを呼び出します。デフォルトでは、スレッドはライセンスを保持していないため、ブロックされて一時停止されます。unpark(thread)メソッドを使用すると、スレッドスレッドはpark()メソッドから戻る前にライセンスを取得できます。

public static void main(String[] args) throws InterruptedException {

        Thread thread = new Thread(() ->{
            String name = Thread.currentThread().getName();
            System.out.println(name + " begin park");
            LockSupport.park();// 如果调用park的线程已经获得了关联的许可证,就会立即返回
            System.out.println(name + " end park");
        },"A");
        thread.start(); // 默认情况下,thread不持有许可证,会被阻塞挂起

        Thread.sleep(1000); 

        System.out.println(thread.getName() + " begin unpark");

        LockSupport.unpark(thread);//让thread获得许可证

    }// 结果如下
A begin park
A begin unpark
A end park

ここでのライセンスの役割を理解する必要があります。スレッドにライセンスを与えることもできますそうすれば、公園が塞がれることはありません

public static void main(String[] args) {
        System.out.println("begin park");
        // 使当前线程获得许可证
        LockSupport.unpark(Thread.currentThread());
        // 再次调用park方法,因为已经有许可证了,不会被阻塞
        LockSupport.park();
        System.out.println("end park");
    }// 结果如下
begin park
end park

プレゼンテーションを中断する

スレッドが中断された場合、parkメソッドは例外をスローしないため、パークの終了後に中断ステータスを処理する必要があります。

public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            String name = Thread.currentThread().getName();
            System.out.println(name + " begin park");
            // 一直挂起自己,只有被中断,才会推出循环
            while (!Thread.currentThread().isInterrupted()) {
                LockSupport.park();
            }
            System.out.println(name + " end park");
        }, "A");
        thread.start();
        Thread.sleep(1000);
        System.out.println("主线程准备中断线程" + thread.getName());
        // 中断thread
        thread.interrupt();
    }// 结果如下
A begin park
主线程准备中断线程A
A end park

ブロッカーの役割

JDK 1.6以降、一連のパークメソッドは、現在のスレッドが待機しているオブジェクトを識別するためのブロッカーパラメータの受け渡しをサポートし始めました。スレッドがライセンスなしでパークメソッドを呼び出し、ブロックおよび一時停止されると、ブロッカーオブジェクトは次のようになります。ブロックされています。スレッドにログインします。

public static void park(Object blocker) {
        Thread t = Thread.currentThread();
        setBlocker(t, blocker); // 设置blocker
        UNSAFE.park(false, 0L);
        setBlocker(t, null); // 清除blocker
    }

Threadクラスには揮発性のObjectparkBlocker変数があります。これは、parkメソッドによって渡されたブロッカーオブジェクトを格納するために使用されます。つまり、blocker変数は、parkメソッドを呼び出すスレッドのメンバー変数に格納されます。

次に、2つの例を通してそれを感じてみましょう:

ブロッカーなしでテスト

public class TestParkWithoutBlocker {
    public void park(){
        LockSupport.park();
    }

    public static void main(String[] args) throws InterruptedException {
        new TestParkWithoutBlocker().park();
        Thread.sleep(3000);
    }
}

jpsコマンドを使用して現在実行中のプロセス4412TestParkを一覧表示してから、jstack4412コマンドを使用してスレッドスタックを表示します。

Javaの同時実行性:スレッドの一時停止とウェイクアップLockSupportツールクラスの詳細

 

ブロッカーでテスト

public class TestBlockerPark {

    public void park(){
        LockSupport.park(this); // 传入blocker = this
    }

    public static void main(String[] args) throws InterruptedException {
        new TestBlockerPark().park();
        Thread.sleep(3000);
    }
}

 

Javaの同時実行性:スレッドの一時停止とウェイクアップLockSupportツールクラスの詳細

 

明らかな違いは、blockerパラメーターを指定したparkメソッドを使用すると、jstackを介して特定のブロッキングオブジェクトに関する情報を確認できることです。

- parking to wait for  <0x000000076b77dff0> (a chapter6_1_LockSupport.TestBlockerPark)

診断ツールはgetBlocker(Thread)メソッドを呼び出して、ブロッカーオブジェクトを取得できます。JDKでは、blockerパラメーターを指定してparkメソッドを使用し、ブロッカーをこれに設定して、トラブルシューティング時にどのクラスがブロックされているかを確認することをお勧めします。印刷スレッドスタックの問題。

JDKが提供するデモ

古い伝統、JavaDocのユースケースを抜粋:

/**
 * 先进先出的锁,只有队列的首元素可以获取锁
 */
class FIFOMutex {
    private final AtomicBoolean locked = new AtomicBoolean(false);
    private final Queue<Thread> waiters
            = new ConcurrentLinkedQueue<Thread>();

    public void lock() {
        // 中断标志
        boolean wasInterrupted = false; 
        Thread current = Thread.currentThread();
        waiters.add(current);

        // 不是队首线程 或 当前锁已经被其他线程获取,则调用park方法挂起自己
        while (waiters.peek() != current ||
                !locked.compareAndSet(false, true)) {
            LockSupport.park(this);
            // 如果park方法是因为被中断而返回,则忽略中断,并且重置中断标志
            // 接着再次进入循环
            if (Thread.interrupted()) // ignore interrupts while waiting
                wasInterrupted = true;
        }
        
        waiters.remove();
        // 如果标记为true,则中断线程
        // [虽然我对中断信号不感兴趣,忽略它,但是不代表其他线程对该标志不感兴趣,因此恢复一下.]
        if (wasInterrupted)          // reassert interrupt status on exit
            current.interrupt();
    }

    public void unlock() {
        locked.set(false);
        LockSupport.unpark(waiters.peek());
    }
}

総括する

LockSupportは、スレッドがパークを一時停止し、パーク解除をウェイクアップするための静的メソッドを提供します。

JDK1.6以降では、ブロッカーオブジェクトを渡すことができるようになりました。これは、問題の監視とトラブルシューティングに便利です。

パークのスレッドが中断された場合、例外はスローされないため、中断ステータスを自分で処理する必要があります。

元のリンク:https://www.cnblogs.com/summerday152/p/14290036.html

この記事がお役に立てば幸いです。私の公式アカウントをフォローし、キーワード[インタビュー]に返信して、Javaのコアナレッジポイントとインタビューギフトパッケージをまとめてください。共有する技術的な乾物の記事や関連資料がもっとあります。みんなが一緒に学び、進歩できるようにしましょう!

おすすめ

転載: blog.csdn.net/weixin_48182198/article/details/112776091