Java并發(fā)編程系列之LockSupport的用法
1、什么是LockSupport?
LockSupport是用于創(chuàng)建鎖和其他同步類的基本線程阻塞原語
2、兩類基本API
LockSupport提供了兩類最基本的API:
block線程類:一般都是以pack開頭的方法名,pack*(...)
pack方法有兩個重載的版本:blocker是一個對象,用于指定阻塞哪個對象。不知道的情況,默認以鎖對象自己this為blocker
public static void park(); public static void park(Object blocker);
拓展:parkNanos函數(shù)
public static void parkNanos(Object blocker, long nanos) {
if (nanos > 0) {
// 獲取當前線程
Thread t = Thread.currentThread();
// 設(shè)置Blocker
setBlocker(t, blocker);
// 獲取許可,并設(shè)置了時間
UNSAFE.park(false, nanos);
// 設(shè)置許可,重新設(shè)置blocker為null,避免unpack,獲取的blocker為之前設(shè)置的
setBlocker(t, null);
}
}
nanos參數(shù)表示相對時間,表示等待多長時間
parkUntil函數(shù):表示在指定的時限前禁用當前線程,deadline參數(shù)表示絕對時間,表示指定的時間
public static void parkUntil(Object blocker, long deadline) {
// 獲取當前線程
Thread t = Thread.currentThread();
// 設(shè)置Blocker
setBlocker(t, blocker);
UNSAFE.park(true, deadline);
// 設(shè)置Blocker為null
setBlocker(t, null);
}
unBlock線程類:unpack(Thread)
unpack方法用于釋放許可,指定線程可以繼續(xù)運行。
3、LockSupport本質(zhì)
LockSupport是一個許可的信號量機制,pack消費,unpack放入,放入也是僅一個,不累計。例如,調(diào)用unpack放入一個信號量,多次調(diào)用,這個是不會累計信號量的,pack調(diào)用之后會消費
4、LockSupport例子
例子:如何控制兩個線程依次打印1、2、3、4、5、6、…
import java.util.concurrent.locks.LockSupport;
public class LockSupportExample {
private static final int total = 10;
private static int i = 0;
static Thread t1 , t2;
public static void main(String[] args) {
t1 = new Thread(() ->{
while (i < total) {
System.out.println("t1:" + (++i));
LockSupport.unpark(t2);
LockSupport.park();
}
});
t2 = new Thread(() -> {
while (i < total) {
LockSupport.park();
System.out.println("t2:" + (++i));
LockSupport.unpark(t1);
}
});
t1.start();
t2.start();
}
}
打?。?/p>
t1: 1
t2: 2
t1:3
t2:4
t1:5
t2:6
t1:7
t2:8
t1:9
t2:10
5、LockSupport源碼
public class LockSupport {
// Hotspot implementation via intrinsics API
private static final sun.misc.Unsafe UNSAFE;
private static final long parkBlockerOffset;
private static final long SEED;
private static final long PROBE;
private static final long SECONDARY;
static {
try {
// 獲取Unsafe實例
UNSAFE = sun.misc.Unsafe.getUnsafe();
// 線程類的class對象
Class<?> tk = Thread.class;
// 獲取Thread的parkBlocker字段的內(nèi)存偏移地址
parkBlockerOffset = UNSAFE.objectFieldOffset
(tk.getDeclaredField("parkBlocker"));
// 獲取Thread的threadLocalRandomSeed字段的內(nèi)存偏移地址
SEED = UNSAFE.objectFieldOffset
(tk.getDeclaredField("threadLocalRandomSeed"));
// 獲取Thread的threadLocalRandomProbe字段的內(nèi)存偏移地址
PROBE = UNSAFE.objectFieldOffset
(tk.getDeclaredField("threadLocalRandomProbe"));
// 獲取Thread的threadLocalRandomSecondarySeed字段的內(nèi)存偏移地址
SECONDARY = UNSAFE.objectFieldOffset
(tk.getDeclaredField("threadLocalRandomSecondarySeed"));
} catch (Exception ex) { throw new Error(ex); }
}
}
pack方法的源碼:
public static void park(Object blocker) {
// 獲取當前線程
Thread t = Thread.currentThread();
// 設(shè)置Blocker
setBlocker(t, blocker);
// 獲取許可
UNSAFE.park(false, 0L);
// 重新可運行后再此設(shè)置Blocker為null,避免unpack獲取到上一個設(shè)置的setBlocker(t, blocker);
setBlocker(t, null);
}
unpack的源碼:
public static void unpark(Thread thread) {
if (thread != null) // 線程為不空
UNSAFE.unpark(thread); // 釋放該線程許可
}
可以看出,不管是pack的源碼還是unpack的源碼都是通過Unsafe的底層api實現(xiàn)的
sun.misc.Unsafe可以直接進行底層非安全操作的工具類
主要提供如下操作:
- 線程掛起與恢復(fù)
- CAS操作
- 操縱對象屬性
- 操縱數(shù)組元素
- 直接操縱內(nèi)存
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
Java實現(xiàn)冒泡排序算法及對其的簡單優(yōu)化示例
這篇文章主要介紹了Java實現(xiàn)冒泡排序算法及對其的簡單優(yōu)化示例,冒泡排序的最差時間復(fù)雜度為O(n^2),最優(yōu)時間復(fù)雜度為O(n),存在優(yōu)化的余地,需要的朋友可以參考下2016-05-05
java設(shè)計模式學(xué)習(xí)之工廠方法模式
這篇文章主要介紹了java設(shè)計模式學(xué)習(xí)之工廠方法模式,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-10-10
IDEA JeeSite框架httpSession.invalidate()無效問題解決方案
這篇文章主要介紹了IDEA JeeSite框架httpSession.invalidate()無效問題解決方案,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-09-09
JVM教程之Java代碼編譯和執(zhí)行的整個過程(二)
這篇文章主要介紹了JVM學(xué)習(xí)筆記第二篇,關(guān)于Java代碼編譯和執(zhí)行的整個過程,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-03-03
java 方法泛型入?yún)和String的重載關(guān)系詳解
這篇文章主要介紹了java 方法泛型入?yún)和String的重載關(guān)系詳解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-02-02

