文章目錄
1.介紹
一個線程是執行程序中的一個線程。Java虛擬機允許應用程序具有多個併發運行的執行線程。
每個線程都有一個優先級。具有較高優先級的線程優先於具有較低優先級的線程執行。每個線程可能會也可能不會被標記爲守護程序。當在某個線程中運行的代碼創建新Thread
對象時,新線程的優先級最初設置爲與創建線程的優先級相等,並且當且僅當創建線程是守護程序時,該線程纔是守護程序線程。
當Java虛擬機啓動時,通常只有一個非守護程序線程(通常調用main
某個指定類的命名方法 )。Java虛擬機將繼續執行線程,直到發生以下任何一種情況:
exit
類的方法Runtime
已被調用,安全管理器SecurityManager
已允許進行退出操作。- 不是守護程序線程的所有線程都已死亡,要麼通過從調用返回到
run
方法,要麼拋出一個傳播到run
方法之外的異常。
有兩種方法可以創建新的執行線程。
- 一種是定義一個繼承Thread類的子類,子類可覆寫父類的
run()
方法 - 另一種是實現Runnable接口
上述引用自API文檔:https://docs.oracle.com/javase/1.4.2/docs/api/
Thread繼承樹如下:
可知Thread類也是實現了Runnable接口
2.提供的常量
//常量:最低優先級
public static final int MIN_PRIORITY = 1;
//常量:默認優先級
public static final int NORM_PRIORITY = 5;
//常量:最高優先級
public static final int MAX_PRIORITY = 10;
3.本地方法
3.1 私有的本地方法
這些是提供給Thread類的元操作
/* Some private helper methods */
private native void setPriority0(int newPriority);
private native void stop0(Object o);
private native void suspend0();
private native void resume0();
private native void interrupt0();
private static native void clearInterruptEvent();
private native void setNativeName(String name);
private native void start0();
3.2 公有的本地方法
//向調度程序提示當前線程願意放棄當前使用的處理器。調度程序可以隨意忽略此提示
public static native void yield();
//測試此線程是否仍然存在。如果線程已經啓動但尚未死亡,則該線程是活動的。
public final native boolean isAlive();
//獲取當前線程
@HotSpotIntrinsicCandidate
public static native Thread currentThread();
//註冊成本地方法
private static native void registerNatives();
//指定的毫秒數
public static native void sleep(long millis) throws InterruptedException;
@HotSpotIntrinsicCandidate
註解是Java 9引入的新特性,在HotSpot中都有一套高效的實現,該高效實現基於CPU指令,運行時,HotSpot維護的高效實現會替代JDK的源碼實現,從而獲得更高的效率。補充引用自:https://blog.csdn.net/javaer_lee/article/details/87161952
4.基本屬性及方法
/* 保留供JVM專用的字段 */
private boolean stillborn = false;
private long eetop;
/* 線程的類加載器 */
private ClassLoader contextClassLoader;
/* 此線程的繼承的 */
private AccessControlContext inheritedAccessControlContext;
/* 用於自動編號匿名線程. */
private static int threadInitNumber;
/* 與此線程有關的線程本地值表,該映射由ThreadLocal類提供 */
ThreadLocal.ThreadLocalMap threadLocals = null;
/* 繼承的線程本地值表 */
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
/* 此線程請求的堆棧大小 */
private final long stackSize;
/**
* 該參數供 java.util.concurrent.locks.LockSupport.park.調用
* 由 (private) java.util.concurrent.locks.LockSupport.setBlocker設置
* 通過java.util.concurrent.locks.LockSupport.getBlocker訪問
*/
volatile Object parkBlocker;
/*以下三個最初未初始化的字段僅由類java.util.concurrent.ThreadLocalRandom管理。
這些字段用於在併發代碼中構建高性能PRNG,因此我們不會冒意外共享的風險,
因此,這些字段使用@Contended隔離。*/
/** The current seed for a ThreadLocalRandom */
@jdk.internal.vm.annotation.Contended("tlr")
long threadLocalRandomSeed;
/** Probe hash value; nonzero if threadLocalRandomSeed initialized */
@jdk.internal.vm.annotation.Contended("tlr")
int threadLocalRandomProbe;
/** Secondary seed isolated from public ThreadLocalRandom sequence */
@jdk.internal.vm.annotation.Contended("tlr")
int threadLocalRandomSecondarySeed;
4.1 線程ID
/* 本線程的ID */
private final long tid;
public long getId() {
return tid;
}
/* 用於在構造函數裏生成新線程ID */
private static long threadSeqNumber;
private static synchronized int nextThreadNum() {
return threadInitNumber++;
}
4.2 線程名稱
public final synchronized void setName(String name) {
checkAccess();
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name;
if (threadStatus != 0) {
setNativeName(name);//本地方法:用於設置線程名稱
}
}
public final String getName() {
return name;
}
4.3 線程狀態
需要注意的是:JAVA定義的6種狀態是JVM的線程狀態,而不是操作系統
/* 線程狀態枚舉 */
public enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
}
private volatile int threadStatus;
//返回此線程的狀態。此方法設計用於監視系統狀態,而不用於同步控制。
public State getState() {
// get current thread state
return jdk.internal.misc.VM.toThreadState(threadStatus);
}
4.4 守護進程
Java中存在兩類線程:User Thread(用戶線程)、Daemon Thread(守護線程) ,其中守護線程是運行在後臺爲用戶線程提供服務的線程,例如GC回收器
。
需要注意的是,
- 當所有用戶線程結束後,只剩下守護線程時,
JVM
便會退出 - 創建線程對象後,必須在調用start方法前,設置守護線程,否則將會拋出
IllegalThreadStateException
異常。 - 在守護線程中產生的新線程也是守護線程
更多與守護進程相關的知識點可以看下這篇文章,寫的很清晰了
//屬性
private boolean daemon = false;
/**
* 設置守護進程方法
* @throws IllegalThreadStateException 若設置守護線程時線程活躍拋出該異常
*/
public final void setDaemon(boolean on) {
checkAccess();
if (isAlive()) {
throw new IllegalThreadStateException();
}
daemon = on;
}
/**
* 確定當前正在運行的線程是否具有修改此線程的權限
* @throws SecurityException 不具修改權限將拋出該異常.
*/
public final void checkAccess() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkAccess(this);
}
}
4.5 線程優先級
需要注意的是:當線程中的run()方法代碼裏面又創建了一個新的線程對象時,新創建的線程優先級和父線程優先級一樣
/*優先級屬性*/
private int priority;
public final void setPriority(int newPriority) {
ThreadGroup g;
checkAccess();
if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
throw new IllegalArgumentException();
}
if((g = getThreadGroup()) != null) {
if (newPriority > g.getMaxPriority()) {
newPriority = g.getMaxPriority();
}
setPriority0(priority = newPriority);
}
}
public final int getPriority() {
return priority;
}
4.5 線程組
private ThreadGroup group;
public final ThreadGroup getThreadGroup() {
return group;
}
public static int enumerate(Thread tarray[]) {
return currentThread().getThreadGroup().enumerate(tarray);
}
5.初始化線程
5.1 靜態塊
registerNatives()
用於註冊本地方法,主要作用就是將C/C++中的方法映射到Java中的native方法。
/* Make sure registerNatives is the first thing <clinit> does. */
private static native void registerNatives();
static {
registerNatives();
}
5.2 公有的構造函數
public Thread() {
this(null, null, "Thread-" + nextThreadNum(), 0);
}
public Thread(Runnable target) {
this(null, target, "Thread-" + nextThreadNum(), 0);
}
Thread(Runnable target, AccessControlContext acc) {
this(null, target, "Thread-" + nextThreadNum(), 0, acc, false);
}
public Thread(ThreadGroup group, Runnable target) {
this(group, target, "Thread-" + nextThreadNum(), 0);
}
public Thread(String name) {
this(null, null, name, 0);
}
public Thread(ThreadGroup group, String name) {
this(group, null, name, 0);
}
public Thread(Runnable target, String name) {
this(null, target, name, 0);
}
public Thread(ThreadGroup group, Runnable target, String name) {
this(group, target, name, 0);
}
public Thread(ThreadGroup group, Runnable target, String name,
long stackSize) {
this(group, target, name, stackSize, null, true);
}
public Thread(ThreadGroup group, Runnable target, String name,
long stackSize, boolean inheritThreadLocals) {
this(group, target, name, stackSize, null, inheritThreadLocals);
}
5.3 私有的構造函數的實現
/**
* 初始化線程
* @param g 所屬線程組
* @param target 實現Runnable接口用於執行的對象
* @param name 新線程名稱
* @param stackSize 新線程堆棧大小, 爲0時表示該參數被忽略
* @param acc 用於繼承的訪問控制上下文,可爲null
* @param inheritThreadLocals 如果值爲true,從構造線程繼承可繼承線程局部變量的初始值
*/
private Thread(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
/* 1.設置線程名 */
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name;
/* 2.爲設置線程組的準備過程 */
//獲取父級線程
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(
SecurityConstants.SUBCLASS_IMPLEMENTATION_PERMISSION);
}
}
//增加線程組中未啓動線程的數量。(需要注意的是,未啓動的線程不會添加到線程組中)
g.addUnstarted();
/*3.正式創建實例過程*/
this.group = g;
this.daemon = parent.isDaemon();
this.priority = parent.getPriority();
if (security == null || isCCLOverridden(parent.getClass()))
this.contextClassLoader = parent.getContextClassLoader();
else
this.contextClassLoader = parent.contextClassLoader;
this.inheritedAccessControlContext =
acc != null ? acc : AccessController.getContext();
this.target = target;
setPriority(priority);
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
this.stackSize = stackSize;
this.tid = nextThreadID();
}
6.線程方法
6.1 start
這個過程實際上是兩個線程在同時運行:當前線程(從調用到返回 start方法)和另一個線程(執行其 run方法)
private Runnable target;
//讓線程開始執行,同時虛擬機會調用該線程的run方法
public synchronized void start() {
//0對應於狀態“ NEW”,
if (threadStatus != 0)
throw new IllegalThreadStateException();
//通知組該線程即將開始,以便可以將其添加到組的線程列表中,並且可以減少該組的未啓動計數
group.add(this);
boolean started = false;
try {
start0();//本地方法
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
//如果start0拋出了Throwable,則它將被向上傳遞到調用堆棧
}
}
}
//若run方法沒有被覆寫,那麼它會執行實現了Runnable接口的對象(target)裏的run方法
@Override
public void run() {
if (target != null) {
target.run();
}
}
6.2 sleep
使當前正在執行的線程進入休眠狀態(暫時停止執行)達指定的時間。
該線程不會失去任何監視器的所有權。
//本地方法:指定的毫秒數
public static native void sleep(long millis) throws InterruptedException;
//指定的毫秒數 加上 指定的納秒數。
public static void sleep(long millis, int nanos)
throws InterruptedException {
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
if (nanos > 0 && millis < Long.MAX_VALUE) {
millis++;
}
sleep(millis);
}
6.3 onSpinWait
告訴調用者暫時無法執行程序,直到某些行爲發生。
/*源碼*/
@HotSpotIntrinsicCandidate
public static void onSpinWait() {}
API示例:
考慮一個類中的一個方法,該方法會循環輪詢,直到在該方法外設置了一些標誌爲止。
需要注意的是,對該onSpinWait
方法的調用應放在旋轉循環內。
class EventHandler {
volatile boolean eventNotificationNotReceived;
void waitForEventAndHandleIt() {
while ( eventNotificationNotReceived ) {
java.lang.Thread.onSpinWait();
}
readAndProcessEvent();
}
void readAndProcessEvent() {
// Read event from some source and process it
. . .
}
}
6.4 interrupt
/* 線程的中斷狀態-由JVM直接讀取/寫入 */
private volatile boolean interrupted;
//判斷當前是不是中斷狀態,不會影響中斷狀態
public boolean isInterrupted() {
return interrupted;
}
//測試當前線程是否已被中斷。通過此方法可以清除線程的 中斷狀態。
//換句話說,如果要連續兩次調用此方法,則第二個調用將返回false(除非在第一個調用清除了其中斷狀態之後且在第二個調用對其進行檢查之前,當前線程再次被中斷)。
· public static boolean interrupted() {
Thread t = currentThread();
boolean interrupted = t.interrupted;
if (interrupted) {
t.interrupted = false;
clearInterruptEvent();//本地方法:清除中斷
}
return interrupted;
}
//TODO:這部分我還是不怎麼理解它的機制
private volatile Interruptible blocker;
private final Object blockerLock = new Object();
//中斷此線程
public void interrupt() {
//如果是其他的進程調用中斷,通過checkAccess()檢測權限
if (this != Thread.currentThread()) {
checkAccess();
// 線程可能在I/O操作中被阻止
synchronized (blockerLock) {
Interruptible b = blocker;
if (b != null) {
interrupted = true;
interrupt0(); // 本地方法:通知虛擬機中斷
b.interrupt(this);
return;
}
}
}
interrupted = true;
interrupt0();
}
6.5 join
public final void join() throws InterruptedException {
join(0);//0意味着永遠等待
}
public final synchronized void join(final long millis)
throws InterruptedException {
if (millis > 0) {
if (isAlive()) {
//獲取納秒爲單位的時間
final long startTime = System.nanoTime();
long delay = millis;
do {
wait(delay);
} while (isAlive() && (delay = millis -
TimeUnit.NANOSECONDS
.toMillis(System.nanoTime() - startTime)) > 0);
}
} else if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
throw new IllegalArgumentException("timeout value is negative");
}
}
//等待最多millis毫秒 加 nanos納秒的時間
public final synchronized void join(long millis, int nanos)
throws InterruptedException {
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
//存在正納秒值會向上取整
if (nanos > 0 && millis < Long.MAX_VALUE) {
millis++;
}
join(millis);
}
6.6 exit
這是一個給系統調用的方法,使Thread 在實際退出之前有機會進行清理
private void exit() {
if (threadLocals != null && TerminatingThreadLocal.REGISTRY.isPresent()) {
TerminatingThreadLocal.threadTerminated();
}
if (group != null) {
group.threadTerminated(this);
group = null;
}
/* Aggressively null out all reference fields: see bug 4006245 */
target = null;
/* Speed the release of some of these resources */
threadLocals = null;
inheritableThreadLocals = null;
inheritedAccessControlContext = null;
blocker = null;
uncaughtExceptionHandler = null;
}
6.7. activeCount
//返回當前線程的線程組及其子組中活動線程的數量的估計值。該值僅爲估值,用於調試
public static int activeCount() {
return currentThread().getThreadGroup().activeCount();
}
6.8 processQueue
static void processQueue(ReferenceQueue<Class<?>> queue,
ConcurrentMap<? extends
WeakReference<Class<?>>, ?> map)
{
Reference<? extends Class<?>> ref;
while((ref = queue.poll()) != null) {
map.remove(ref);
}
}
7.線程上下文類加載器
@CallerSensitive
public ClassLoader getContextClassLoader() {
if (contextClassLoader == null)
return null;
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
ClassLoader.checkClassLoaderPermission(contextClassLoader,
Reflection.getCallerClass());
}
return contextClassLoader;
}
public void setContextClassLoader(ClassLoader cl) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("setContextClassLoader"));
}
contextClassLoader = cl;
}
補充:關於類加載器一時半會解釋不清楚,以後寫個專門的文章來分析
@CallerSensitive
註解可以看下這篇文章@CallerSensitive 註解的作用
8.線程異常捕獲
提供的接口
@FunctionalInterface
public interface UncaughtExceptionHandler {
void uncaughtException(Thread t, Throwable e);
}
提供的方法
private volatile UncaughtExceptionHandler uncaughtExceptionHandler;
//用於對特定的線程設置異常處理器。
public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
checkAccess();
uncaughtExceptionHandler = eh;
}
//用於獲取特定的線程的異常處理器。
public UncaughtExceptionHandler getUncaughtExceptionHandler() {
//若當前的線程沒有異常處理器,會使用所屬線程組的異常處理器
return uncaughtExceptionHandler != null ?
uncaughtExceptionHandler : group;
}
private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler;
//靜態方法:用於設置一個默認的全局異常處理器
public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(
new RuntimePermission("setDefaultUncaughtExceptionHandler")
);
}
defaultUncaughtExceptionHandler = eh;
}
//靜態方法:用於獲取一個默認的全局異常處理器
public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler(){
return defaultUncaughtExceptionHandler;
}
詳見我的另一篇博客:
Java 線程異常處理—UncaughtExceptionHandler
9.Stack
private static native StackTraceElement[][] dumpThreads(Thread[] threads);
private static native Thread[] getThreads();
public static void dumpStack() {
new Exception("Stack trace").printStackTrace();
}
public StackTraceElement[] getStackTrace() {
if (this != Thread.currentThread()) {
// check for getStackTrace permission
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkPermission(
SecurityConstants.GET_STACK_TRACE_PERMISSION);
}
// optimization so we do not call into the vm for threads that
// have not yet started or have terminated
if (!isAlive()) {
return EMPTY_STACK_TRACE;
}
StackTraceElement[][] stackTraceArray = dumpThreads(new Thread[] {this});
StackTraceElement[] stackTrace = stackTraceArray[0];
// a thread that was alive during the previous isAlive call may have
// since terminated, therefore not having a stacktrace.
if (stackTrace == null) {
stackTrace = EMPTY_STACK_TRACE;
}
return stackTrace;
} else {
return (new Exception()).getStackTrace();
}
}
public static Map<Thread, StackTraceElement[]> getAllStackTraces() {
// check for getStackTrace permission
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkPermission(
SecurityConstants.GET_STACK_TRACE_PERMISSION);
security.checkPermission(
SecurityConstants.MODIFY_THREADGROUP_PERMISSION);
}
// Get a snapshot of the list of all threads
Thread[] threads = getThreads();
StackTraceElement[][] traces = dumpThreads(threads);
Map<Thread, StackTraceElement[]> m = new HashMap<>(threads.length);
for (int i = 0; i < threads.length; i++) {
StackTraceElement[] stackTrace = traces[i];
if (stackTrace != null) {
m.put(threads[i], stackTrace);
}
// else terminated so we don't put it in the map
}
return m;
}
10.Caches
/** cache of subclass security audit results */
/* Replace with ConcurrentReferenceHashMap when/if it appears in a future
* release */
private static class Caches {
/** cache of subclass security audit results */
static final ConcurrentMap<WeakClassKey,Boolean> subclassAudits =
new ConcurrentHashMap<>();
/** queue for WeakReferences to audited subclasses */
static final ReferenceQueue<Class<?>> subclassAuditsQueue =
new ReferenceQueue<>();
}
/**
* Verifies that this (possibly subclass) instance can be constructed
* without violating security constraints: the subclass must not override
* security-sensitive non-final methods, or else the
* "enableContextClassLoaderOverride" RuntimePermission is checked.
*/
private static boolean isCCLOverridden(Class<?> cl) {
if (cl == Thread.class)
return false;
processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits);
WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue);
Boolean result = Caches.subclassAudits.get(key);
if (result == null) {
result = Boolean.valueOf(auditSubclass(cl));
Caches.subclassAudits.putIfAbsent(key, result);
}
return result.booleanValue();
}
private static boolean auditSubclass(final Class<?> subcl) {
Boolean result = AccessController.doPrivileged(
new PrivilegedAction<>() {
public Boolean run() {
for (Class<?> cl = subcl;
cl != Thread.class;
cl = cl.getSuperclass())
{
try {
cl.getDeclaredMethod("getContextClassLoader", new Class<?>[0]);
return Boolean.TRUE;
} catch (NoSuchMethodException ex) {
}
try {
Class<?>[] params = {ClassLoader.class};
cl.getDeclaredMethod("setContextClassLoader", params);
return Boolean.TRUE;
} catch (NoSuchMethodException ex) {
}
}
return Boolean.FALSE;
}
}
);
return result.booleanValue();
}
11.WeakClassKey
/**
* Weak key for Class objects.
**/
static class WeakClassKey extends WeakReference<Class<?>> {
/**
* saved value of the referent's identity hash code, to maintain
* a consistent hash code after the referent has been cleared
*/
private final int hash;
/**
* Create a new WeakClassKey to the given object, registered
* with a queue.
*/
WeakClassKey(Class<?> cl, ReferenceQueue<Class<?>> refQueue) {
super(cl, refQueue);
hash = System.identityHashCode(cl);
}
/**
* Returns the identity hash code of the original referent.
*/
@Override
public int hashCode() {
return hash;
}
}
12.過時方法
/*
作用:獲得計算堆棧幀的數量
過時原因:結果從未得到明確定義,並且取決於線程的掛起。
此方法可能會在Java SE的將來版本中刪除。
*/
@Deprecated(since="1.2", forRemoval=true)
public int countStackFrames() {
throw new UnsupportedOperationException();
}
/*
作用:強制線程停止執行。
1.如果安裝了安全管理器,則將其作爲參數調用其checkAccess方法。
這可能會導致引SecurityException(在當前線程中)。
2.如果此線程與當前線程不同(也就是說,當前線程正在嘗試停止除自身之外的其他線程),
則另外調用安全管理器的checkPermission方法(帶有RuntimePermission(“ stopThread”)參數)。 同樣,這可能導致拋出SecurityException(在當前線程中)。
該線程代表的線程被迫停止正在執行的異常操作,並拋出新創建的ThreadDeath對象作爲異常。
允許停止尚未啓動的線程。如果線程最終啓動,則它立即終止。
除非必須執行一些特殊的清理操作,否則應用程序通常不應嘗試捕獲ThreadDeath
(請注意,拋出ThreadDeath會導致try語句的finally子句在線程正式死亡之前被執行)。
如果catch子句捕獲了ThreadDeath對象,則重要的是重新拋出該對象,以便線程實際上死亡。
如果未捕獲的異常是ThreadDeath的實例,則對未捕獲的異常做出反應的頂級錯誤處理程序不會打印出消息,也 不會以其他方式通知應用程序
過時原因:此方法僅適用於與suspend一起使用,因爲不贊成使用死鎖,因此已棄用。
*/
@Deprecated(since="1.2")
public final void stop() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
checkAccess();
if (this != Thread.currentThread()) {
security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
}
}
// 狀態值零對應於“ NEW”,它不能更改爲NOT-NEW,因爲我們持有鎖
if (threadStatus != 0) {
resume(); //如果線程被掛起,則將其喚醒;
}
// VM可以處理所有線程狀態
stop0(new ThreadDeath());
}
/**
作用:恢復掛起的線程。
首先,不帶參數調用此線程的checkAccess方法。 這可能導致拋出SecurityException(在當前線程中)。
如果線程處於活動狀態但已掛起,則將繼續執行該線程並允許其執行。
過時原因:此方法僅適用於與suspend一起使用,因爲不贊成使用死鎖,因此已棄用。
*/
@Deprecated(since="1.2", forRemoval=true)
public final void resume() {
checkAccess();
resume0();
}
/**
作用:掛起該線程。
首先,不帶參數調用此線程的checkAccess方法。 這可能導致拋出SecurityException(在當前線程中)。
如果線程處於活動狀態,則將其掛起,並且除非繼續進行操作,否則它將不會進一步進行。
棄用原因:此方法已被棄用,因爲它容易死鎖。
如果目標線程在掛起時在監視器上持有鎖以保護關鍵系統資源,則在恢復目標線程之前,沒有線程可以訪問該資 源。 如果將恢復目標線程的線程在調用resume之前嘗試鎖定此監視器,則會導致死鎖。
這種僵局通常表現爲“凍結”進程。
*/
@Deprecated(since="1.2", forRemoval=true)
public final void suspend() {
checkAccess();
suspend0();
}