Java?LockSupport常用方法的源碼分析
LockSupport類常用方法源碼
LockSupport只是一個簡單的基礎(chǔ)類,位于java.util.concurrent.locks包下,多用于線程的阻塞和喚醒,因此LockSupport也被稱為其他線程的工具類。
LockSupport類的源碼有標注,LockSupport類無法實例化。LockSupport類的底層是有Unsafe類實現(xiàn)的,LockSupport加載時的初始化也用到了Unsafe獲取成員的偏移量,其源碼如下:
// 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 = sun.misc.Unsafe.getUnsafe();
Class<?> tk = Thread.class;
parkBlockerOffset = UNSAFE.objectFieldOffset
(tk.getDeclaredField("parkBlocker"));
SEED = UNSAFE.objectFieldOffset
(tk.getDeclaredField("threadLocalRandomSeed"));
PROBE = UNSAFE.objectFieldOffset
(tk.getDeclaredField("threadLocalRandomProbe"));
SECONDARY = UNSAFE.objectFieldOffset
(tk.getDeclaredField("threadLocalRandomSecondarySeed"));
} catch (Exception ex) { throw new Error(ex); }
}LockSupport類中有一些核心的線程操作方法,多用于線程的阻塞與喚醒。
調(diào)用park()方法使線程阻塞:
public static void park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
UNSAFE.park(false, 0L);
setBlocker(t, null);
}
private static void setBlocker(Thread t, Object arg) {
// Even though volatile, hotspot doesn't need a write barrier here.
UNSAFE.putObject(t, parkBlockerOffset, arg);
}
調(diào)用park(Object blocker)對傳入的線程進行阻塞
public static void park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
UNSAFE.park(false, 0L);
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);
}
在nanos的時間范圍內(nèi)阻塞傳入的線程:
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 unpark(Thread thread) {
if (thread != null)
UNSAFE.unpark(thread);
}wait/notify方法和park/unpark方法區(qū)別
LockSupport類中的方法還有很多,在此先列舉到這里。當我們看到阻塞和喚醒方法時,我們會聯(lián)想到另一組喚醒方法wait()和notify(),這兩組方法還是有所區(qū)別的。
這里直接記錄下結(jié)論:wait和notify方法只能在同步代碼塊中使用(即必須與synchronized連用);必須先執(zhí)行wait方法,然后再執(zhí)行notify方法喚醒線程,調(diào)換順序的話線程仍處于阻塞狀態(tài)。
而park()和unpark()方法與之不同,這里可以通過代碼運行結(jié)果來看:
package XIAOWEI;
import java.util.concurrent.locks.LockSupport;
???????public class Xiaowei{
public static void main(String[] args) {
Thread A = new Thread(()-> {
System.out.println("線程A已經(jīng)被阻塞QWQ");
LockSupport.park();
System.out.println("線程A被線程B喚醒啦~~~");
});
A.start();
new Thread(()->{
System.out.println("線程B在喚醒線程A ing~~~");
LockSupport.unpark(A);
},"B").start();
}
}
那如果我們先通過線程B喚醒線程A,然后再讓線程A阻塞呢(讓線程A的阻塞休眠兩秒)?
package XIAOWEI;
import java.util.concurrent.locks.LockSupport;
public class Xiaowei {
public static void main(String[] args) {
Thread A = new Thread(()-> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("線程A已經(jīng)被阻塞QWQ(第二版)");
LockSupport.park();
System.out.println("線程A被線程B喚醒啦~~~(第二版)");
});
A.start();
new Thread(()->{
System.out.println("線程B在喚醒線程A ing~~~駕駕駕");
LockSupport.unpark(A);
},"B").start();
}
}
由上面輸出結(jié)果來看,雖然線程B先喚醒了線程A,然后線程A再開始阻塞,但是線程A還是處于喚醒狀態(tài),這是為什么呢?
接下來我找了段LockSupport類中的注釋,其實有時看看注釋也挺有意思的哈哈:
* <p>This class associates, with each thread that uses it, a permit
* (in the sense of the {@link java.util.concurrent.Semaphore
* Semaphore} class). A call to {@code park} will return immediately
* if the permit is available, consuming it in the process; otherwise
* it <em>may</em> block. A call to {@code unpark} makes the permit
* available, if it was not already available. (Unlike with Semaphores
* though, permits do not accumulate. There is at most one.)
這段話大意是說,LockSupport類使用permits這個東西來實現(xiàn)線程的阻塞和喚醒。每一個線程都會使用到(擁有)permit,且permit的值默認為0。接著它又說,這個概念和Semaphore信號量差不多,但是permit的值只有0和1兩個值。哦~原來是這樣。
對于上面例子,線程B調(diào)用unpark方法喚醒A后,會使得線程A的permit值為1,當線程調(diào)用park方法使自己阻塞時,發(fā)現(xiàn)自己已經(jīng)有許可(permit)了,就會繼續(xù)向下執(zhí)行業(yè)務,而不會阻塞不動。
到此這篇關(guān)于Java LockSupport常用方法的源碼分析的文章就介紹到這了,更多相關(guān)Java LockSupport內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Idea進行pull的時候Your local changes would be
這篇文章主要介紹了Idea進行pull的時候Your local changes would be overwritten by merge.具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-11-11
Spring Boot Admin實現(xiàn)服務健康預警功能
這篇文章主要介紹了Spring Boot Admin實現(xiàn)服務健康預警功能,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-05-05
Spring Boot2開發(fā)之Spring Boot整合Shiro兩種詳細方法
這篇文章主要介紹了Spring Boot2開發(fā)之Spring Boot整合Shiro詳細方法,需要的朋友可以參考下2020-03-03
SPRINGBOOT讀取PROPERTIES配置文件數(shù)據(jù)過程詳解
這篇文章主要介紹了SPRINGBOOT讀取PROPERTIES配置文件數(shù)據(jù)過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2019-12-12

