我們知道各種並發框架如CountDownLatch、CyclicBarrier和Semaphore是基於AQS (AbstractQueuedSynchronizer)框架實現的,AQS框架借助於兩個類:
- Unsafe(提供CAS操作) //JDK9以后引入了VarHandle變量句柄,代替了Unsafe
- LockSupport(提供park/unpark操作)
而LockSupport的park和unpark的實現是依賴於Unsafe類的prak和unpark的。重載方法中可以傳入一個blocker對象,在dump線程時能獲得更多的信息,用於問題排查或系統監控。
public static void park() {
U.park(false, 0L); //U = Unsafe.getUnsafe();
}
public static void park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
U.park(false, 0L);
setBlocker(t, null);
}
那么Unsafe類是個什么東西呢?Unsafe的全限定名是sun.misc.Unsafe。在源碼的注釋中我們可以看到:執行低級、不安全操作的方法集合。從名字就知道它是不安全的,它的功能有很多,比如:volatile的讀寫一個變量的field,有序的寫一個變量的field,直接內存操作:申請內存,釋放內存,CAS的修改變量等。
本文主要說說park和unpark方法。最簡單的理解:park阻塞一個線程,unpark喚醒一個線程。
核心設計原理:“許可”。park方法本質是消費許可,如果沒有可消費的許可,那么就阻塞當前線程,一直等待,直到阻塞線程的unpark方法被其他線程調用,然后消費許可,當前線程被喚醒,繼續執行。unpark方法本質是生產許可,一個線程剛創建出來,然后運行,此時是沒有許可的,所以unpark方法可以在park方法前調用。下次park方法調用時,直接消費許可,線程不用阻塞等待許可。許可最多只有一個,連續多次調用unpark只能生產一個許可。
park方法有幾種重載的形式,可以設置等待時間,等待時間可以設置為絕對的或者相對的,超過等待時間,線程會自動被喚醒。
底層實現原理:
mutex和condition保護了一個_counter的變量,簡單點說:當park時,這個變量被設置為0,當unpark時,這個變量被設置為1。