LockSupport是用來建立鎖和其餘同步類的基本線程阻塞原語。
LockSupport中的park() 和 unpark() 的做用分別是阻塞線程和解除阻塞線程,並且park()和unpark()不會遇到「Thread.suspend 和 Thread.resume所可能引起的死鎖」問題。
由於park() 和 unpark()有許可的存在;調用 park() 的線程和另外一個試圖將其 unpark() 的線程之間的競爭將保持活性。java
concurrent包是基於AQS (AbstractQueuedSynchronizer)框架,AQS框架藉助於兩個類:Unsafe(提供CAS操做)和LockSupport(提供park/unpark操做)。所以,LockSupport可謂構建concurrent包的基礎之一。框架
歸根結底,LockSupport調用的Unsafe中的native代碼: 函數
public native void unpark(Thread jthread); public native void park(boolean isAbsolute, long time);
兩個函數聲明清楚地說明了操做對象:park函數是將當前Thread阻塞,而unpark函數則是將另外一個Thread喚醒。this
與Object類的wait/notify機制相比,park/unpark有兩個優勢:1. 以thread爲操做對象更符合阻塞線程的直觀定義;2. 操做更精準,能夠準確地喚醒某一個線程(notify隨機喚醒一個線程,notifyAll喚醒全部等待的線程),增長了靈活性。spa
在上面的文字中,我使用了阻塞和喚醒,是爲了和wait/notify作對比。其實park/unpark的設計原理核心是「許可」。park是等待一個許可。unpark是爲某線程提供一個許可。若是某線程A調用park,那麼除非另一個線程調用unpark(A)給A一個許可,不然線程A將阻塞在park操做上。線程
有一點比較難理解的,是unpark操做能夠再park操做以前。也就是說,先提供許可。當某線程調用park時,已經有許可了,它就消費這個許可,而後能夠繼續運行。這實際上是必須的。考慮最簡單的生產者(Producer)消費者(Consumer)模型:Consumer須要消費一個資源,因而調用park操做等待;Producer則生產資源,而後調用unpark給予Consumer使用的許可。很是有可能的一種狀況是,Producer先生產,這時候Consumer可能尚未構造好(好比線程還沒啓動,或者還沒切換到該線程)。那麼等Consumer準備好要消費時,顯然這時候資源已經生產好了,能夠直接用,那麼park操做固然能夠直接運行下去。若是沒有這個語義,那將很是難以操做。設計
1 import java.util.concurrent.locks.LockSupport; 2 3 public class LockSupportTest1 { 4 5 private static Thread mainThread; 6 7 public static void main(String[] args) { 8 9 ThreadA ta = new ThreadA("ta"); 10 // 獲取主線程 11 mainThread = Thread.currentThread(); 12 13 System.out.println(Thread.currentThread().getName()+" start ta"); 14 ta.start(); 15 16 System.out.println(Thread.currentThread().getName()+" block"); 17 // 主線程阻塞 18 LockSupport.park(mainThread); 19 20 System.out.println(Thread.currentThread().getName()+" continue"); 21 } 22 23 static class ThreadA extends Thread{ 24 25 public ThreadA(String name) { 26 super(name); 27 } 28 29 public void run() { 30 System.out.println(Thread.currentThread().getName()+" wakup others"); 31 // 喚醒「主線程」 32 LockSupport.unpark(mainThread); 33 } 34 } 35 }
運行結果:code
main start ta main block ta wakup others main continue
說明:park和wait的區別。wait讓線程阻塞前,必須經過synchronized獲取同步鎖。對象
1 public class WaitTest1 { 2 3 public static void main(String[] args) { 4 5 ThreadA ta = new ThreadA("ta"); 6 7 synchronized(ta) { // 經過synchronized(ta)獲取「對象ta的同步鎖」 8 try { 9 System.out.println(Thread.currentThread().getName()+" start ta"); 10 ta.start(); 11 12 System.out.println(Thread.currentThread().getName()+" block"); 13 // 主線程等待 14 ta.wait(); 15 16 System.out.println(Thread.currentThread().getName()+" continue"); 17 } catch (InterruptedException e) { 18 e.printStackTrace(); 19 } 20 } 21 } 22 23 static class ThreadA extends Thread{ 24 25 public ThreadA(String name) { 26 super(name); 27 } 28 29 public void run() { 30 synchronized (this) { // 經過synchronized(this)獲取「當前對象的同步鎖」 31 System.out.println(Thread.currentThread().getName()+" wakup others"); 32 notify(); // 喚醒「當前對象上的等待線程」 33 } 34 } 35 } 36 }