LockSupport
LocalSupport類特性
- 不可實例化
private LockSupport() {} // Cannot be instantiated.
LockSupport的方法都是靜態方法
私有變量
private static final sun.misc.Unsafe UNSAFE;
private static final long parkBlockerOffset;
私有變量:unsafe
- sun.misc.Unsafe可以直接操控內存。被JDK廣泛用於自己的包中,如java.nio和java.util.concurrent
- API十分不安全、不輕便、而且不穩定。不建議在生產環境中使用
- 這個不安全的類提供了一個觀察HotSpot JVM內部結構並且可以對其進行修改。有時它可以被用來在不適用C++調試的情況下學習虛擬機內部結構,有時也可以被拿來做性能監控和開發工具
私有變量: parkBlockerOffset
- 被LockSupport的setBlocker和getBlocker調用
- 這個對象是用來記錄線程被阻塞時被誰阻塞的,用於線程監控和分析工具來定位原因
LockSupport.java
/**
* 通過反射機制獲取Thread類的parkBlocker字段對象。然後通過
* sun.misc.Unsafe對象的objectFieldOffset方法獲取到
* parkBlocker在內存裏的偏移量
*/
parkBlockerOffset = UNSAFE.objectFieldOffset
(tk.getDeclaredField("parkBlocker"));
Thread.java
/**
* The argument supplied to the current call to
* java.util.concurrent.locks.LockSupport.park.
* Set by (private) java.util.concurrent.locks.LockSupport.setBlocker
* Accessed using java.util.concurrent.locks.LockSupport.getBlocker
*/
volatile Object parkBlocker;
JVM的實現可以自由選擇如何實現Java對象的“佈局”,也就是在內存裏Java對象的各個部分放在哪裏,包括對象的實例字段和一些元數據等。
sun.misc.Unsafe裏關於對象字段訪問的方法把對象佈局抽象出來,它提供了objectFieldOffset()方法用於獲取某個字段相對 Java對象的“起始地址”的偏移量,也提供了getInt、getLong、getObject之類的方法可以使用前面獲取的偏移量來訪問某個Java 對象的某個字段
爲什麼要用偏移量來獲取對象?不直接調用get/set方法?
parkBlocker就是在線程處於阻塞的情況下才會被賦值。線程都已經阻塞了,如果不通過這種內存的方法,而是直接調用線程內的方法,線程是不會迴應調用的
LockSupport Method
- LockSupport中有且只有一個私有方法
- 對給定線程t的parkBlocker賦值。爲了防止這個parkBlocker被誤用,該方法是不對外公開的
private static void setBlocker(Thread t, Object arg) {
// Even though volatile, hotspot doesn't need a write barrier here.
UNSAFE.putObject(t, parkBlockerOffset, arg);
}
參數
- Thread t 需要被賦值Blocker的線程
- Object arg 具體的Blocker對象
- 從線程t中獲取它的parkBlocker對象,即返回的是阻塞線程t的Blocker對象
public static Object getBlocker(Thread t) {
if (t == null)
throw new NullPointerException();
return unsafe.getObjectVolatile(t, parkBlockerOffset);
}
以park開頭的方法,用於阻塞線程
帶blocker參數的park方法
public static void park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
UNSAFE.park(false, 0L);
setBlocker(t, null);
}
public static void parkNanos(Object blocker, long nanos) {
if (nanos > 0) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
UNSAFE.park(false, nanos);
setBlocker(t, null);
}
}
public static void parkUntil(Object blocker, long deadline) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
UNSAFE.park(true, deadline);
setBlocker(t, null);
}
參數:
- Object blocker:用於記錄到線程中的parkBlocker對象。
- nanos:在nanos時間後線程自動恢復掛起
- deadline:在deadline時刻線程自動(這個毫秒其實就是自1970年1月1日0時起的毫秒數)
不帶blocker參數的park方法
public static void park() {
UNSAFE.park(false, 0L);
}
public static void parkNanos(long nanos) {
if (nanos > 0)
UNSAFE.park(false, nanos);
}
public static void parkUntil(long deadline) {
UNSAFE.park(true, deadline);
}
- 沒有做parkBlocker的賦值操作
以unpark開頭的方法,用於解除阻塞
public static void unpark(Thread thread) {
if (thread != null)
UNSAFE.unpark(thread);
}
park與unpark命令是成對出現的。unpark必須要在park命令後執行。但是線程的恢復並不一定要用unpark, 因爲park的時間參數,有些情況下線程會自己恢復