標籤:idt name nano 設定 pos nan 異常 ted 對象
簡述
LockSupport 是一個非常方便實用的線程阻塞工具,它可以線上程內任意位置讓線程阻塞。
和 Thread.suspend()相比,它彌補了由於 resume()在前發生,導致線程無法繼續執行的情況。
和 Object.wait()相比,它不需要先獲得某個對象的鎖,也不會拋出 InterruptedException 異常。
LockSupport 的靜態方法 park()可以阻塞當前線程,類似的還有 parkNanos()、parkUntil()等方法。它們實現了一個限時等待,如所示:
執行個體
1 import java.util.concurrent.locks.LockSupport; 2 /** 3 * Created by zhengbinMac on 2017/3/5. 4 */ 5 public class SuspendResumeTest { 6 public static Object object = new Object(); 7 static TestThread t1 = new TestThread("線程1"); 8 static TestThread t2 = new TestThread("線程2"); 9 public static class TestThread extends Thread{10 public TestThread(String name) {11 super.setName(name);12 }13 @Override14 public void run() {15 synchronized (object) {16 System.out.println(getName()+" 佔用。。");17 // Thread.currentThread().suspend();18 LockSupport.park();19 System.out.println(Thread.currentThread().getName()+" 執行結束!");20 }21 }22 }23 public static void main(String[] args) throws InterruptedException {24 t1.start();25 Thread.sleep(200);26 t2.start();27 // t1.resume();28 LockSupport.unpark(t1);29 LockSupport.unpark(t2);30 // t2.resume();31 t1.join();32 t2.join();33 }34 }
代碼只是對Java多線程——到期的suspend()掛起、resume()繼續執行線程中執行個體稍作修改,將 suspend()和 resume()改為 park()與 unpark()。
修改後,同樣的問題:我們依然無法保證 unpark()方法發生在 park()之後,但是多次執行代碼,發現始終都可以正常結束,不會因為兩方法的順序導致線程永久性掛起。
這是因為,其使用類似訊號量的機制。
它為每個線程準備了一個許可,如果許可可用,那麼 park()方法立即返回,並消費這個許可(將許可變為不可用);如果許可不可用,則阻塞。
而 unpark()方法,則是使一個許可變為可用。
上述特點使得:即使 unpark()操作發生在 park()之前,它也可以使下一次得 park()操作立即返回。這是上述執行個體代碼順利結束的原因。
同時,park()掛起的線程不會像 suspend()那樣線程狀態為 RUNNABLE,park()會明確給出 WAITING 狀態,並標註由 park()引起,如所示:
這個標註,使得分析問題時更加方便,可以使用 park(Object)方法,為當前線程設定一個阻塞對象,這個阻塞對象會出現線上程 Dump 中。
將執行個體中 18 行改為:
LockSupport.park(this);
jstack 輸出為:
參考資料
[1] 實戰Java高並發程式設計, 3.1.7 - 線程阻塞工具類:LockSupport
[2] Java並發編程的藝術, 5.5 - LockSupport工具
Java多線程——線程阻塞工具類LockSupport