Thread源碼分析
- 一.概述
- 二.源碼解析
- 1.重要的全局變量
- 2.內部枚舉類State
- 3. nextThreadNum方法
- 4. nextThreadID方法
- 5.常用的構造方法
- 6. currentThread方法
- 7. setPriority方法
- 8. start方法
- 9. run方法
- 10. exit方法
- 11. interrupt方法
- 12. interrupted方法
- 13. isInterrupted方法
- 14. isAlive方法
- 15. getPriority方法
- 16. setName方法
- 17. getName方法
- 18. getThreadGroup方法
- 19. activeCount方法
- 20. join方法
- 21. setDaemon方法
- 22. isDaemon方法
- 23. toString方法
- 24. getContextClassLoader方法
- 25. setContextClassLoader方法
- 26. holdsLock方法
- 27. getId方法
- 28. getState方法
- 29. yield方法
- 30. sleep方法
- 31. stop方法
- 32. suspend方法
- 33. resume方法
一.概述
Java虛擬機允許應用程序同時運行多個運行線程。
每個線程都有優先級,優先級高的線程可以被優先執行。當一個線程中創建了另一個新線程,新線程的優先級默認等於這個線程的優先級。只有守護線程創建的線程纔是守護線程。
當一個Java虛擬機啓動時,通常會啓動一個非守護線程,來運行main方法。虛擬機將繼續執行此線程,直到以下情況發生:
1)調用Runtime類的exit方法,並且安全管理器允許退出操作發生。
2)除了守護線程之外的所有線程都已經死亡。即線程內代碼全部執行完返回,或線程運行時拋出異常。
每個線程都有一個名字,用於識別線程創建的目的。多個線程可能有相同的名字。若創建了一個沒有指定名字的線程,則會自動爲其生成一個名字。
Thread.java中的相關代碼:
public class Thread implements Runnable {
// native方法
private static native void registerNatives();
// 靜態代碼塊初始化
static {
registerNatives();
}
…
}
1.實現了Runnable接口,可以在線程中運行。
2.在靜態代碼塊中調用registerNatives方法,確保該方法第一個執行。registerNatives方法用於動態註冊native方法,將java方法和native方法進行關聯。
二.源碼解析
1.重要的全局變量
Thread.java中的相關代碼:
private volatile String name; // 用於記錄線程的名字
private int priority; // 用於記錄線程的優先級
private boolean daemon = false; // 用於表示線程是否爲守護線程
private Runnable target; // 用於保存線程要執行的代碼
private ThreadGroup group; // 用於記錄線程所在的組
private ClassLoader contextClassLoader; // 用於保存上下文類加載器
// 用於根據封裝的上下文對系統資源訪問做出決策
private AccessControlContext inheritedAccessControlContext;
private static int threadInitNumber; // 用於匿名線程的自動編號
ThreadLocal.ThreadLocalMap threadLocals = null; // 用於保存當前線程共享的對象
// 用於保存從父線程繼承的共享對象
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
private long stackSize; // 當前線程請求的堆棧大小,默認爲0
private long tid; // 用於保存線程ID
private static long threadSeqNumber; // 用於自動生成線程ID
private volatile int threadStatus = 0; // 用於表示線程的狀態,0表示線程尚未啓動
// 在可中斷I/O操作中阻塞此線程的對象(如果有的話)。
// 應在設置此線程的中斷狀態後調用攔截器的中斷方法。
private volatile Interruptible blocker;
private final Object blockerLock = new Object(); // 用於同步鎖
public final static int MIN_PRIORITY = 1; // 線程最小優先級
public final static int NORM_PRIORITY = 5; // 線程默認的優先級
public final static int MAX_PRIORITY = 10; // 線程最大優先級
// 允許子類重寫上下文類加載器權限
private static final RuntimePermission SUBCLASS_IMPLEMENTATION_PERMISSION =
new RuntimePermission("enableContextClassLoaderOverride");
2.內部枚舉類State
用來表示線程的狀態。
Thread.java中的相關代碼:
public enum State {
// 尚未啓動的線程的狀態
NEW,
// 可運行的線程的狀態
// 可能在Java虛擬機中執行,也可能在等在操作系統的其它資源
RUNNABLE,
// 獲取不到鎖的線程的狀態
// 阻塞狀態的線程可能正在等待獲取鎖來執行同步方法或代碼塊
// 或在調用wait方法釋放鎖後,又需要鎖來執行同步方法或代碼塊
BLOCKED,
// 等待的線程的狀態
// 等待狀態的線程正在等待另一個線程的特定操作
// 調用wait方法不指定超時時間、調用join方法不指定超時時間,
// 線程將進入該狀態
// 一個線程調用鎖對象的wait方法,需要等待另一個線程調用該鎖對象
// 的notify 或notifyAll方法
// 一個線程調用join方法,需要等待一個指定的線程終止
WAITING,
// 指定了等待時間等待的線程的狀態
// 調用sleep方法、調用wait方法指定超時時間、調用join方法指定超時時間
// 線程將處於該狀態
TIMED_WAITING,
// 終止的線程的狀態
// 線程已經執行完畢
TERMINATED;
}
3. nextThreadNum方法
當創建線程不指定線程名稱時,調用此方法產生編號作爲線程名稱的一部分。
Thread.java中的相關代碼:
private static synchronized int nextThreadNum() {
// 返回,自增
return threadInitNumber++;
}
4. nextThreadID方法
用於創建線程ID。
Thread.java中的相關代碼:
private static synchronized long nextThreadID() {
// 自增,返回
return ++threadSeqNumber;
}
5.常用的構造方法
1)無參數
Thread.java中的相關代碼:
public Thread() {
// 調用四個參數的init方法
// 默認線程名爲”Thread-自增編號“
// 堆棧大小0,表示忽略該參數
init(null, null, "Thread-" + nextThreadNum(), 0);
}
2)參數爲Runnable
Thread.java中的相關代碼:
public Thread(Runnable target) {
// 調用四個參數的init方法
// 保存target,默認線程名爲”Thread-自增編號“
// 堆棧大小0,表示忽略該參數
init(null, target, "Thread-" + nextThreadNum(), 0);
}
3)參數爲String
Thread.java中的相關代碼:
public Thread(String name) {
// 調用四個參數的init方法
// 堆棧大小0,表示忽略該參數
init(null, null, name, 0);
}
4)參數爲ThreadGroup、Runnable、String、long
Thread.java中的相關代碼:
public Thread(ThreadGroup group, Runnable target, String name,
long stackSize) {
// 調用四個參數的init方法
init(group, target, name, stackSize);
}
5)四個參數的init方法
Thread所有的構造方法都調用該方法來實現,用來對線程進行初始化。
Thread.java中的相關代碼:
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
// 調用五個參數的init方法,默認AccessControlContext爲空
init(g, target, name, stackSize, null);
}
6)五個參數的init方法
線程初始化的核心實現。相比四個參數的init方法,多了一個AccessControlContext類型的參數。
Thread.java中的相關代碼:
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc) {
// 若線程名字爲空,則拋出異常
if (name == null) {
throw new NullPointerException("name cannot be null");
}
// 保存線程的名字到全局變量
this.name = name;
// 獲取創建當前線程的線程,相當於當前線程的父線程
Thread parent = currentThread();
// 獲取安全管理器,默認是關閉的
SecurityManager security = System.getSecurityManager();
// 若線程組爲空
if (g == null) {
// 若開啓了安全管理器
if (security != null) {
// 獲取安全管理器的線程組
g = security.getThreadGroup();
}
// 若安全管理器沒有配置線程組
if (g == null) {
// 獲取當前線程父線程的線程組
g = parent.getThreadGroup();
}
}
// 檢查權限,是否允許訪問
g.checkAccess();
// 若開啓了安全管理器
if (security != null) {
// 若當前類(可能是子類)的實例可以在不違反安全約束的條件下創建
if (isCCLOverridden(getClass())) {
// 安全管理器檢查權限是否允許子類重寫上下文類加載器
security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
}
}
// 通知線程組,增加一個未開始的線程
g.addUnstarted();
// 保存線程組到全局變量
this.group = g;
// 判斷父線程是否爲守護線程,將結果保存到全局變量
this.daemon = parent.isDaemon();
// 當前線程的優先級和父線程的優先級相同
this.priority = parent.getPriority();
// 若安全管理器沒有開啓,
// 或父線程的類的實例可以在不違反安全約束的條件下創建
if (security == null || isCCLOverridden(parent.getClass()))
// 調用方法,將父線程的上下文類加載器保存到全局變量
// 因爲當父線程的類可以不違法安全約束創建實例,說明他可能存在子類,
// 即子類化。由於多態,調用getContextClassLoader可能由子類實現
this.contextClassLoader = parent.getContextClassLoader();
else // 若安全管理器開啓,並且創建父線程的類的實例違反安全約束
// 調用靜態變量,將父線程的上下文類加載器保存到全局變量
// 因爲創建父線程類的實例違反安全規約,所以不可能存在子類
// 因此直接從父類的靜態變量中獲取
this.contextClassLoader = parent.contextClassLoader;
// 若存取控制上下文爲空,從AccessController中獲取
// 否則直接保存到全局變量
this.inheritedAccessControlContext =
acc != null ? acc : AccessController.getContext();
// 保存線程需要執行的Runnable對象
this.target = target;
// 設置線程優先級
setPriority(priority);
// 若父線程中存在繼承的ThreadLocal
if (parent.inheritableThreadLocals != null)
// 則根據父進程中繼承的ThreadLocal創建一個ThreadLocalMap對象
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
// 保存堆棧大小到全局變量
this.stackSize = stackSize;
// 設置線程ID
tid = nextThreadID();
}
6. currentThread方法
獲取當前執行的線程。
Thread.java中的相關代碼:
public static native Thread currentThread();
7. setPriority方法
設置線程優先級。
Thread.java中的相關代碼:
public final void setPriority(int newPriority) {
ThreadGroup g;
// 檢查當前運行的線程是否擁有修改此線程的權限
// 詳解在1)處
checkAccess();
// 若要設置的線程優先級超過最大優先級或小於最小優先級,則拋出異常
if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
throw new IllegalArgumentException();
}
// 獲取線程組,若線程組不爲空
// 詳解在2)處
if((g = getThreadGroup()) != null) {
// 若要設置的優先級超過了線程組的最大優先級
if (newPriority > g.getMaxPriority()) {
// 將要設置的優先級改爲線程組的最大優先級
newPriority = g.getMaxPriority();
}
// 將優先級保存到全局變量
// 調用setPriority0方法設置線程優先級
// 詳解在3)處
setPriority0(priority = newPriority);
}
}
1)checkAccess方法
檢查當前運行的線程是否擁有修改此線程的權限。
Thread.java中的相關代碼:
public final void checkAccess() {
// 獲取安全管理器
SecurityManager security = System.getSecurityManager();
// 若開啓了安全管理
if (security != null) {
// 通過安全管理器檢查當前運行的線程是否擁有修改此線程的權限
security.checkAccess(this);
}
}
2)getThreadGroup方法
獲取線程組。
Thread.java中的相關代碼:
public final ThreadGroup getThreadGroup() {
// 返回全局變量
return group;
}
3)setPriority0方法
設置線程優先級的核心方法。
Thread.java中的相關代碼:
private native void setPriority0(int newPriority);
8. start方法
啓動線程。
調用該方法將使JVM執行線程的run方法。
Thread.java中的相關代碼:
public synchronized void start() {
// 若當前線程的狀態不爲0,即不是新創建尚未啓動的狀態
if (threadStatus != 0)
// 則拋出異常
throw new IllegalThreadStateException();
// 通知線程組,該線程已啓動
group.add(this);
// 用於判斷啓動狀態,設置false
boolean started = false;
try {
// 啓動線程
// 詳解在1)處
start0();
// 設置true
started = true;
} finally {
// 若發生異常
try {
// 若線程沒有啓動
if (!started) {
// 通知線程組線程啓動失敗
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
// 若start0方法拋出異常,則什麼都不做,它的值會傳給調用的堆棧。
}
}
}
1)start0方法
線程啓動的核心方法。
Thread.java中的相關代碼:
private native void start0();
9. run方法
線程執行的核心方法。
若該線程通過傳入Runnable對象創建,則調用Runnable的run方法。
若該線程通過繼承Thread類實現,則需要重寫Run方法。
Thread.java中的相關代碼:
@Override
public void run() {
// 若target不爲空,即線程通過傳入Runnable對象創建
if (target != null) {
// 調用run方法
target.run();
}
}
10. exit方法
該方法被系統調用,用於在線程退出前,對線程進行清理。
Thread.java中的相關代碼:
private void exit() {
// 若線程組不爲空
if (group != null) {
// 通知線程組
group.threadTerminated(this);
// 釋放引用
group = null;
}
// 釋放Runnable對象
target = null;
// 釋放其它資源
threadLocals = null;
inheritableThreadLocals = null;
inheritedAccessControlContext = null;
blocker = null;
uncaughtExceptionHandler = null;
}
11. interrupt方法
用於中斷一個線程。
Thread.java中的相關代碼:
public void interrupt() {
// 若調用該方法的線程不是本線程
if (this != Thread.currentThread())
checkAccess(); // 檢查權限,是否允許訪問
// 同步鎖
synchronized (blockerLock) {
// 獲取中斷攔截器
Interruptible b = blocker;
// 若中斷攔截器不爲空
if (b != null) {
// 設置線程中斷標誌位
// 詳解在1)處
interrupt0();
// 調用中斷攔截器的方法
b.interrupt(this);
// 返回
return;
}
}
// 若沒有中斷攔截器,直接設置線程中斷標誌位
interrupt0();
}
1)interrupt0方法
中斷核心方法,該方法會設置線程中斷標誌位。
Thread.java中的相關代碼:
private native void interrupt0();
12. interrupted方法
判斷當前線程是否中斷。
調用該方法將清除線程的中斷標誌位。
Thread.java中的相關代碼:
public static boolean interrupted() {
// 獲取當前線程,調用isInterrupted方法判斷
return currentThread().isInterrupted(true);
}
13. isInterrupted方法
判斷調用該方法的線程對象是否中斷
1)無參數
Thread.java中的相關代碼:
public boolean isInterrupted() {
// 調用了重載方法
return isInterrupted(false);
}
2)參數爲boolean
判斷線程中斷的核心方法。
中斷狀態的將被重置。重置的值不取決於參數ClearInterrupted。
Thread.java中的相關代碼:
private native boolean isInterrupted(boolean ClearInterrupted);
14. isAlive方法
判斷線程是否存活。
存活即線程開始運行但並沒有死亡的期間。
Thread.java中的相關代碼:
public final native boolean isAlive();
15. getPriority方法
獲取線程優先級。
Thread.java中的相關代碼:
public final int getPriority() {
// 直接返回
return priority;
}
16. setName方法
設置線程的名字。
Thread.java中的相關代碼:
public final synchronized void setName(String name) {
// 檢查權限,是否允許訪問
checkAccess();
// 若名字爲空,則拋出異常
if (name == null) {
throw new NullPointerException("name cannot be null");
}
// 將線程名保存到全局變量
this.name = name;
// 若線程不是新創建未運行的狀態
if (threadStatus != 0) {
// 通知native層處理
// 詳解在1)處
setNativeName(name);
}
}
1)setNativeName方法
設置線程名字的核心方法。
Thread.java中的相關代碼:
private native void setNativeName(String name);
17. getName方法
獲取線程的名字。
Thread.java中的相關代碼:
public final String getName() {
// 直接返回
return name;
}
18. getThreadGroup方法
獲取線程組。
Thread.java中的相關代碼:
public final ThreadGroup getThreadGroup() {
// 直接返回
return group;
}
19. activeCount方法
返回當前線程的線程組及其子線程組中所有活躍線程的數量。
Thread.java中的相關代碼:
public static int activeCount() {
// 獲取當前線程,獲取線程組,遍歷統計
return currentThread().getThreadGroup().activeCount();
}
20. join方法
1)不指定超時時間
當前線程等待在當前線程中調用該方法的線程死亡。
Thread.java中的相關代碼:
public final void join() throws InterruptedException {
// 調用重載方法,超時時間爲0
join(0);
}
2)指定超時時間
若在指定時間內調用該方法的線程沒有執行完畢,則等待的線程將不再等待。
Thread.java中的相關代碼:
public final synchronized void join(long millis, int nanos)
throws InterruptedException {
// 若指定毫秒小於0,則拋出異常
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
// 若納秒小於0或大於999999,則拋出異常
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
// 若納秒超過了500000,則化零爲整,毫秒加一
// 若納秒不爲零且毫秒爲0,則設置最小時間1毫秒
if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
millis++;
}
// 調用重載方法
join(millis);
}
重載的join方法。
最多等待mills毫秒來讓線程死亡,參數爲0表示永久等待。
Thread.java中的相關代碼:
public final synchronized void join(long millis)
throws InterruptedException {
// 獲取系統當前時間作爲時間基準
long base = System.currentTimeMillis();
// 用於計算當前時間到base時間的間隔
long now = 0;
// 若等待時間小於0,則拋出異常
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
// 若等待時間爲0,說明是永久等待
if (millis == 0) {
// 循環,若調用join方法的線程活躍
while (isAlive()) {
// 調用join方法所在的線程永久等待
wait(0);
}
} else { // 不是永久等待
// 循環,若調用join方法的線程活躍
while (isAlive()) {
// 計算還需要等待的時長
long delay = millis - now;
// 若還需要等待的時長小於0,則跳出循環
if (delay <= 0) {
break;
}
// 調用join方法所在的線程等待delay毫秒,超時放棄等待
wait(delay);
// 計算目前已經等待的時間
now = System.currentTimeMillis() - base;
}
}
}
注意:如在線程A中調用線程B的join方法,B爲調用join方法的線程,A爲調用join方法所在的線程。由於join方法中調用了wait方法,因此線程A阻塞等待,線程B正常執行。
21. setDaemon方法
用於標記一個線程是守護線程還是用戶線程。
當唯一運行的線程爲守護線程時,Java虛擬機退出。
該方法必須在線程開始前調用。
Thread.java中的相關代碼:
public final void setDaemon(boolean on) {
// 檢查權限,是否允許訪問
checkAccess();
// 若線程活躍,即已經開始未結束,則拋出異常
if (isAlive()) {
throw new IllegalThreadStateException();
}
// 設置標誌位
daemon = on;
}
22. isDaemon方法
判斷線程是否爲守護線程。
Thread.java中的相關代碼:
public final boolean isDaemon() {
// 直接返回
return daemon;
}
23. toString方法
返回線程對應的字符串形式。
Thread.java中的相關代碼:
public String toString() {
// 獲取線程組
ThreadGroup group = getThreadGroup();
// 若線程組存在
if (group != null) {
// 返回線程名,線程優先級,線程組名稱
return "Thread[" + getName() + "," + getPriority() + "," +
group.getName() + "]";
} else { // 若線程組不存在
// 返回線程名,線程優先級
return "Thread[" + getName() + "," + getPriority() + "," +
"" + "]";
}
}
24. getContextClassLoader方法
獲取線程的上下文類加載器。
Thread.java中的相關代碼:
// 由於代碼中調用getCallerClass方法,所以需要加上該註解
// 詳解在1)處
@CallerSensitive
public ClassLoader getContextClassLoader() {
// 若線程上下文類加載器爲空,則返回null
if (contextClassLoader == null)
return null;
//獲取安全管理器
SecurityManager sm = System.getSecurityManager();
// 若開啓了安全管理器
if (sm != null) {
// 檢查類加載器的權限
ClassLoader.checkClassLoaderPermission(contextClassLoader,
Reflection.getCallerClass());
}
// 返回上下文類加載器
return contextClassLoader;
}
1)CallerSensitive註解
jvm的開發者認爲jdk內有一些方法是危險的,不希望開發者調用,因此將這些方法通過CallerSensitive註解修飾。
所有內部調用getCallerClass方法的方法都必須使用@CallerSensitive進行註解,該方法用來獲取調用該方法的類。在獲取調用該方法的類時,會跳過調用鏈路上所有被@CallerSensitive直接修飾的方法所在的類,避免了多層反射調用時產生不安全的隱患。
25. setContextClassLoader方法
爲線程設置上下文類加載器。
Thread.java中的相關代碼:
public void setContextClassLoader(ClassLoader cl) {
// 獲取安全管理器
SecurityManager sm = System.getSecurityManager();
// 若開啓了安全管理器
if (sm != null) {
// 檢查權限,是否允許設置上下文類加載器
sm.checkPermission(new RuntimePermission("setContextClassLoader"));
}
// 保存到全局變量
contextClassLoader = cl;
}
26. holdsLock方法
判斷當前線程是否持有某個對象的鎖。
Thread.java中的相關代碼:
public static native boolean holdsLock(Object obj);
27. getId方法
獲取線程ID。
Thread.java中的相關代碼:
public long getId() {
return tid;
}
28. getState方法
獲取當前線程的狀態。
該方法用於監控系統狀態,而不是用於同步控制。
Thread.java中的相關代碼:
public State getState() {
return sun.misc.VM.toThreadState(threadStatus);
}
29. yield方法
該方法用於提示線程調度程序,當前線程願意放棄當前處理器的使用。
該方法用來緩解線程對CPU的過度使用。
Thread.java中的相關代碼:
public static native void yield();
30. sleep方法
當前正在執行的線程,在指定的時間內暫停執行。
線程不釋放持有的鎖。
Thread.java中的相關代碼:
public static void sleep(long millis, int nanos)
throws InterruptedException {
// 若毫秒小於0,則拋出異常
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
// 若納秒小於0或大於999999,則拋出異常
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
// 若納秒超過了500000,則化零爲整,毫秒加一
// 若納秒不爲零且毫秒爲0,則設置最小時間1毫秒
if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
millis++;
}
// 調用重載方法
sleep(millis);
}
調用重載的sleep方法。
Thread.java中的相關代碼:
public static native void sleep(long millis) throws InterruptedException;
31. stop方法
用於強制停止線程的執行。
棄用原因:線程在被停止時,停止的線程會突然釋放所有持有的鎖。之前等待這些鎖的對象,可能會產生不確定的行爲。
Thread.java中的相關代碼:
// 該方法已被棄用,不建議使用
@Deprecated
public final void stop() {
// 獲取安全管理器
SecurityManager security = System.getSecurityManager();
// 若開啓了安全管理器
if (security != null) {
// 檢查權限,是否允許訪問
checkAccess();
// 若在一個線程中停止另一個線程
if (this != Thread.currentThread()) {
// 檢查權限
security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
}
}
// 若線程的狀態不是新創建未運行的狀態
if (threadStatus != 0) {
// 若線程被掛起,喚醒線程
resume();
}
// 停止線程運行
// 詳解在1)處
stop0(new ThreadDeath());
}
1)stop0方法
停止線程的核心方法。
Thread.java中的相關代碼:
private native void stop0(Object o);
32. suspend方法
暫停線程的執行,即將線程掛起。
若線程是活躍的,則將線程被掛起,直到線程被恢復,否則不會繼續執行。
棄用原因:容易造成死鎖。當線程被掛起時持有系統關鍵資源的鎖,則在它被恢復之前,其它線程不能訪問該資源。
Thread.java中的相關代碼:
// 該方法已被棄用,不建議使用
@Deprecated
public final void suspend() {
// 檢查權限,是否允許訪問
checkAccess();
// 掛起線程
// 詳解在1)處
suspend0();
}
1)suspend0方法
線程掛起的核心方法。
Thread.java中的相關代碼:
private native void suspend0();
33. resume方法
恢復暫停(掛起)的線程。
棄用原因:此方法需要和suspend方法配合使用,因爲suspend方法易造成死鎖,被棄用,所以該方法也被棄用。
Thread.java中的相關代碼:
// 該方法已被棄用,不建議使用
@Deprecated
public final void resume() {
// 檢查權限,是否允許訪問
checkAccess();
// 恢復線程
// 詳解在1)處
resume0();
}
1)resume0方法
恢復掛起線程的核心方法。
Thread.java中的相關代碼:
private native void resume0();