閱讀620 返回首頁    go 阿裏雲 go 技術社區[雲棲]


LockSupport 源碼閱讀

在java中,要讓線程等待最普通的方法是調用Object.wait()方法,

Causes the current thread to wait until another thread invokes the notify() method for this object.

但是當我閱讀JUC(java.util.concurrent)的源碼時發現這個包不是這樣做的, 我跟蹤CountDownLatch.await()調用,最後跟到了LockSupport.park()方法裏, 這裏調用的是 unsafe.park()方法來block線程。

LockSupport 和 CAS一樣是JUC很多控製機製的基礎(但他們的底層其實都是在依賴Unsafe),下麵就來學習下LockSupport這個類:


// Hotspot implementation via intrinsics API
private static final Unsafe unsafe = Unsafe.getUnsafe(); //unsafe 用來實現底層操作
private static final long parkBlockerOffset; //輔助參數,配合unsafe用的

//This object is recorded while
// the thread is blocked to permit monitoring and diagnostic tools to
// identify the reasons that threads are blocked.
//設置一個線程和關聯的blocker對象,blocker用來做分析,debug用的
private static void setBlocker(Thread t, Object arg) {
// Even though volatile, hotspot doesn’t need a write barrier here.
unsafe.putObject(t, parkBlockerOffset, arg);
}

//block當前線程,是否真的block了取決於permit是否available
//permit相當於1,0的開關, 默認是0, 調一次unpark就+1變成1了,調一次park會消費這個1又變成0了(park立即返回),
//再次調用park會變成block(因為沒有1可以拿了,會等在這,直到有1),這時調用unpark會把1給回去(線程解鎖返回)
//每個線程都有個相關的permit, permit最多一個,調用unpark多次也不會積累
//當為permit available時,方法會立即返回,不會block,反之就會block當前線程直到下麵3件事發生
//1. 其他線程調用了unpark(此線程)
//2. 其他線程interrupts了此線程
//3. The call spuriously (that is, for no reason) returns.
public static void park() {
unsafe.park(false, 0L);
}

//對於給定線程,讓permit變得avaliable,
public static void unpark(Thread thread) {
if (thread != null)
unsafe.unpark(thread);
}

//然後park有2個帶限定時間的版本,所以一共有3個park version, 這3個version又有帶blocker的debug版本
public static void parkNanos(long nanos) {
public static void parkUntil(long deadline) {

下麵寫些代碼試下


System.out.println("start");
LockSupport.parkNanos(1000000000);
System.out.println("end");
//一開始會block線程,直到給定時間過去後才往下走

System.out.println(“start”);
LockSupport.unpark(Thread.currentThread());
LockSupport.parkNanos(1000000000);
System.out.println(“end”);
//不會block,因為一開始給了一個permit

System.out.println(“start”);
LockSupport.unpark(Thread.currentThread());
LockSupport.unpark(Thread.currentThread());
LockSupport.parkNanos(1000000000);
System.out.println(“inter”);
LockSupport.parkNanos(1000000000);
System.out.println(“end”);
//第一個park不會block,第2個會,因為permit不會因為多次調用unpark就積累

最後更新:2017-05-22 14:32:41

  上一篇:go  Java IO: ByteArrayOutputStream
  下一篇:go  lnav:Linux 下一個基於控製台的高級日誌文件查看器