您好,登錄后才能下訂單哦!
本篇內容主要講解“線程阻塞喚醒工具LockSupport怎么使用”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“線程阻塞喚醒工具LockSupport怎么使用”吧!
LockSupport
是 Java 并發編程中一個非常重要的組件,我們熟知的并發組件 Lock、線程池、CountDownLatch
等都是基于 AQS
實現的,而 AQS
內部控制線程阻塞和喚醒又是通過 LockSupport
來實現的。
從該類的注釋上也可以發現,它是一個控制線程阻塞和喚醒的工具,與以往的不同是它解決了曾經 wait()、notify()、await()、signal()
的局限。
我們知道 Java 中實現并發安全通常會通過這兩種加鎖的方式,對于 synchronized
加鎖的方式,如果我們想要控制線程的阻塞和喚醒是通過鎖對象的 wait()
和 notify()
方法,以下面循環交替打印 AB 為例
int status = 2; public static void main(String[] args) throws InterruptedException { TestSync obj = new TestSync(); new Thread(() -> { synchronized (obj){ while (true){ if(obj.status == 1){ obj.wait(); } System.out.println("A"); obj.status = 1; TimeUnit.SECONDS.sleep(1); obj.notify(); } } }).start(); new Thread(() -> { synchronized (obj){ while (true){ if(obj.status == 2){ obj.wait(); } System.out.println("B"); obj.status = 2; TimeUnit.SECONDS.sleep(1); obj.notify(); } } }).start(); }
如果我們使用 Lock
實現類,上述代碼幾乎是一樣的,只是先獲取 Condition
對象
Condition condition = lock.newCondition();
把 obj.wait()
換成 condition.await()
, obj.notify()
換成 condition.signal()
即可。
技術 | 阻塞喚醒方式 | 局限 |
---|---|---|
synchronized | 使用鎖對象的 wait()、notify() | 1. 只能用在 synchronized 包裹的同步代碼塊中 2. 必須先 wait() 才能 notify() |
Lock | 使用 condition 的 await()、signal() | 1. 只能用在 lock 鎖住的代碼塊中 2. 必須先 await() 才能 signal() |
LockSupport | park()、unpark(Thread t) | 沒有限制 |
下面代碼中,我們使用 LockSupport
去阻塞和喚醒線程,我們可以多次嘗試,LockSupport
的 park()
和 unpark()
方法沒有先后順序的限制,也不需要捕獲異常,也沒有限制要在什么代碼塊中才能使用。
public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(() -> { System.out.println("A"); LockSupport.park(); System.out.println("被喚醒"); }); t1.start(); TimeUnit.SECONDS.sleep(2); new Thread(() -> { System.out.println("B"); LockSupport.unpark(t1); }).start(); }
從該類的注釋中我們可以看到這個類存儲了使用它的線程的一個許可證,當調用 park()
方法的時候會判斷當前線程的許可證是否存在,如果存在將直接放行,否則就阻塞。
public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(() -> { try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("A"); LockSupport.park();//不會阻塞 System.out.println("被喚醒"); }); t1.start(); TimeUnit.SECONDS.sleep(2); new Thread(() -> { System.out.println("B"); System.out.println("先調用 unpark()"); LockSupport.unpark(t1); },"t2").start(); }
看這個代碼示例,這里我們在 t2
中先讓線程 t1
unpark()
, 然后在 t1
中調用 park()
, 結果并不會阻塞 t1
線程。因為在 t2
中調用 LockSupport.unpark(t1);
的時候相當于給 t1
提前準備好了許可證。
LockSupport.unpark(t1);
無論調用多少次,t1
的通行證只有一個,當在 t1
中調用兩次 park()
方法時線程依然會被阻塞。
public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(() -> { try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("A"); LockSupport.park(); LockSupport.park(); System.out.println("被喚醒"); }); t1.start(); TimeUnit.SECONDS.sleep(2); new Thread(() -> { System.out.println("B"); System.out.println("先調用 unpark()"); LockSupport.unpark(t1); LockSupport.unpark(t1); LockSupport.unpark(t1); LockSupport.unpark(t1); LockSupport.unpark(t1); },"t2").start(); }
以上述代碼為例,t1
將被阻塞。
觀察源碼發現 park() 和 unpark() 最底下調用的是 native() 方法,源碼在 C++ 中實現
@IntrinsicCandidate public native void park(boolean isAbsolute, long time); @IntrinsicCandidate public native void unpark(Object thread);
到此,相信大家對“線程阻塞喚醒工具LockSupport怎么使用”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。