1. 程式人生 > >併發程式設計(五)LockSupport

併發程式設計(五)LockSupport

併發程式設計(五)LockSupport

LockSupport 提供 park() 和 unpark() 方法實現阻塞執行緒和解除執行緒阻塞,實現的阻塞和解除阻塞是基於“許可(permit)”作為關聯,permit 相當於一個訊號量(0,1),預設是0。 執行緒之間不再需要一個 Object 或者其它變數來儲存狀態,不再需要關心對方的狀態。

一、LockSupport API

(1) pack

方法 說明
park() 掛起當前執行緒
park(Object blocker) 掛起當前執行緒
parkNanos(long nanos) 指定掛起時間(相對於當前的時間),時間到後自動被喚醒
parkNanos(Object blocker, long nanos) 指定掛起時間(相對於當前的時間)
parkUntil(long deadline) 指定掛起時間(絕對時間),時間到後自動被喚醒
parkUntil(Object blocker, long deadline) 指定掛起時間(絕對時間),時間到後自動被喚醒

從上面表格可以看出,park 支援 blocker 物件作為引數,該欄位是 Thread 類,專門為 LockSupport 而設計的。此 blocker 物件線上程受阻塞時被記錄,這樣監視工具和診斷工具就可以確定執行緒受阻塞的原因。建議最好使用這些帶 blocker 的方法版本,而不是不帶 blocker 引數的方法。

public static void park() {
    UNSAFE.park(false, 0L);
}

(2) unpark

設定執行緒許可為可用。

  • 如果執行緒當前已經被 pack 掛起,那麼這個執行緒將會被喚醒。
  • 如果執行緒當前沒有被掛起,那麼下次呼叫 pack 不會掛起執行緒。
public static void unpark(Thread thread) {
    if (thread != null)
        UNSAFE.unpark(thread);
}

二、LockSupport 使用

(1) 先park後unpark

public void test1() throws Exception {
    Thread mainThread = Thread.currentThread();
    Thread thread = new Thread(() -> {
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        System.out.println("before unpark, " + LockSupport.getBlocker(mainThread));
        LockSupport.unpark(mainThread);
        System.out.println("after unpark, " + LockSupport.getBlocker(mainThread));
    });
    thread.start();
    System.out.println("before park");
    // 等待獲取許可
    LockSupport.park("Park");
    System.out.println("after park");
}

結果:

before park
before unpark, Park
after park
after unpark, null

(2) 先unpark後unpark

先執行 unpark,在呼叫 park,直接就沒被阻塞, 因此 park/unpark 相比 wait/notify 更加的靈活

public void test2() throws Exception {
    Thread mainThread = Thread.currentThread();
    Thread thread = new Thread(() -> {
        System.out.println("before unpark, " + LockSupport.getBlocker(mainThread));
        LockSupport.unpark(mainThread);
        System.out.println("after unpark, " + LockSupport.getBlocker(mainThread));
    });
    thread.start();

    TimeUnit.SECONDS.sleep(1);
    System.out.println("before park");
    // 等待獲取許可
    LockSupport.park("Park");
    System.out.println("after park");
}

(2) park與interrupt

public void test3() throws Exception {
    Thread thread = new Thread(() -> {
        System.out.println(Thread.currentThread().isInterrupted()); // false
        LockSupport.park();
        System.out.println(Thread.currentThread().isInterrupted()); // true
    });
    thread.start();

    TimeUnit.SECONDS.sleep(1);
    thread.interrupt();
    System.in.read();
}

簡而言之:

  1. 實現機制和 wait/notify 有所不同,面向的是執行緒
  2. 不需要依賴監視器
  3. 與 wait/notify 沒有交集
  4. 使用起來方便靈活

參考:

  1. 《LockSupport解析與使用》:https://blog.csdn.net/secsf/article/details/78560013

每天用心記錄一點點。內容也許不重要,但習慣很重要!