1、例子
package com.ruigege.LockSourceAnalysis6;
import java.util.concurrent.locks.LockSupport;
public class TestParkAndUnpark {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("child thread begin park");
LockSupport.park();
System.out.println("child thread end park");
System.out.println("今天又學了一個快捷鍵,sysout + alt +/ 是控制檯" +
"輸出的一個快捷鍵");
}
});
thread.start();
Thread.sleep(1000);
System.out.println("main thread begin unpark");
LockSupport.unpark(thread);
}
}
-
-
首先創建了一個子線程,而後調用park方法,因爲默認狀況下,子線程沒有持有許可證,所以它會把本身掛起;在主線程中執行了unpark方法,參數爲子線程,這樣作的目的就是讓子線程可以持有許可證,而後子線程調用的park方法就會返回
-
注意點:park方法不會告訴咱們是由於哪一種緣由返回的,所以調用者須要根據以前調用park方法的緣由,再次檢查條件是否知足,若是不知足的話,還需再次調用park方法
-
例如:根據調用先後的中斷狀態的對比能夠判斷是否是由於被中斷才返回的。
-
下面爲了說明調用park方法後的線程是由於被中斷才返回的,咱們修改代碼
package com.ruigege.LockSourceAnalysis6;
import java.util.concurrent.locks.LockSupport;
public class TestParkAndUnpark {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("child thread begin park");
while(!Thread.currentThread().isInterrupted()) {
LockSupport.park();
}
System.out.println("child thread end park");
System.out.println("今天又學了一個快捷鍵,sysout + alt +/ 是控制檯" +
"輸出的一個快捷鍵");
}
});
thread.start();
Thread.sleep(1000);
System.out.println("main thread begin unpark");
thread.interrupt();
}
}
20.1
-
咱們能夠從中看出,若是隻有中斷了子線程,子線程纔會運行結束,若是子線程不中斷的話,即便調用了LockSupport(thread)方法,也不會中斷。
2、void parkNanos(long nanos)方法
-
與park方法相相似,若是該線程沒有拿到許可證,那麼調用parkNanos(long nanos)方法該線程會當即中止阻塞,並返回;若是有許可證,那麼nanos毫秒以後,該線程纔會返回。
-
package com.ruigege.LockSourceAnalysis6;
import java.util.concurrent.locks.LockSupport;
public class TestPark {
public void testPark() {
LockSupport.park();
}
public static void main(String[] args) {
System.out.println("開始park方法");
TestPark testPark = new TestPark();
testPark.testPark();
}
}
20.2
-
下面是咱們使用parkNanos方法來代替LockSupport.park()方法
LockSupport.park(this);
-
使用這個帶參數的park(Object blocker)方法,當線程在沒有持有許可證的時候,調用park方法,會被阻塞起來,這個blocker對象會被記錄到該線程的內部。
-
使用jstack pid命令能夠對線程堆棧進行查看,該線程內部是含有的什麼對象
3、park(Object blocker)源碼解析
public static void park2(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t,blocker);
UNSAFE.park(false,0L);
setBlocker(t,null);
}
4、void parkNanos(Object blocker,long nanos)方法
5、void parkUtil(Object blocker,long deadline)方法
-
這個方法和parkNanos不一樣的就是超時時間的算法,parkNanos的超時時間是從線程阻塞開始算起的,而parkUtil方法的超時時間是從1970年開始算起,到某一個時間點的毫秒數
public static void parkUtile(Object blocker,long deadline) {
Thread t = Thread.currentThread();
setBlocker(t,blocker);
UNSAFE.park(false,deadline);
setBlocker(t,null);
}
6、下面再看一個例子
package com.ruigege.LockSourceAnalysis6;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.LockSupport;
public class FIFOMutex {
private final AtomicBoolean locked = new AtomicBoolean(false);
private final Queue<Thread> waiters = new ConcurrentLinkedQueue<Thread>();
public void lock() {
boolean wasInterrupted = false;
Thread current = Thread.currentThread();
waiters.add(current);
while(waiters.peek() != current || !locked.compareAndSet(false,true)) {
LockeSupport.park(this);
if(Thread.interrupted()) {
wasInterrupted = true;
}
}
waiters.remove();
if(wasInterrupted) {
current.interrupt();
}
}
public void unlock() {
locked.set(false);
LockSupport.unpark(waiters.peek());
}
}
-
這是一個先進先出的鎖,也就是隻有隊列的首元素能夠獲取鎖,在代碼(1)若是當前線程不是隊首或者當前鎖已經被其餘線程獲取,那麼調用park方法掛起本身。
-
而後再代碼(2)處作判斷,若是park方法是由於被中斷而返回的,則忽略中斷,而且重置中斷標誌,複習該方法去
-
在代碼(3)中,判斷標記,若是標記爲true那麼中斷該線程
-
總結:其實就是其餘線程中斷了該線程,雖然我對中斷信號不感興趣,忽略它(也就是代碼(2)),可是不表明其餘線程對該標誌不感興趣,咱們還須要恢復一下。
7、源碼:
-
所在包:com.ruigege.ConcurrentListSouceCodeAnalysis5
-
https://github.com/ruigege66/ConcurrentJava
-
-
-
歡迎關注微信公衆號:傅里葉變換,我的帳號,僅用於技術交流