Thread類原始碼解析
原始碼版本:jdk8
其中的部分論證和示例程式碼:Java_Concurrency
類宣告:
Thread
本身實現了Runnable
介面
Runnable
:任務,《java程式設計思想》中表示該命名不好,或許叫Task更好;
Thread:執行緒,執行任務的載體;
public class Thread implements Runnable
構造方法:
構造時,可以指定執行緒組,執行緒執行任務Runnable物件,執行緒名和棧大小
執行緒的所有構造方法,都是通過init()
實現
/** * Thread的所有public構造方法傳入的inheritThreadLocals均為true * 只有一個許可權為default的構造方法傳入為false * 所有的構造方法實現均是呼叫了該方法 */ private void init(ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc, boolean inheritThreadLocals) { // 構造方法中傳入的執行緒名不能為null // 預設執行緒名:"Thread-" + nextThreadNum() if (name == null) { throw new NullPointerException("name cannot be null"); } this.name = name; // 被創建出來的執行緒是建立執行緒的子執行緒 Thread parent = currentThread(); // 新建執行緒的執行緒組 // 如果構造方法傳入的執行緒組為null,則通過這個流程來決定其執行緒組,通常,新建執行緒的執行緒組為其建立執行緒的執行緒組 SecurityManager security = System.getSecurityManager(); if (g == null) { /* Determine if it's an applet or not */ /* If there is a security manager, ask the security manager what to do. */ if (security != null) { g = security.getThreadGroup(); } /* If the security doesn't have a strong opinion of the matter use the parent thread group. */ if (g == null) { g = parent.getThreadGroup(); } } /* checkAccess regardless of whether or not threadgroup is explicitly passed in. */ g.checkAccess(); /* * Do we have the required permissions? */ if (security != null) { if (isCCLOverridden(getClass())) { security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION); } } g.addUnstarted(); this.group = g; // 子執行緒預設擁有父執行緒的優先順序和daemon屬性 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); /* Stash the specified stack size in case the VM cares */ this.stackSize = stackSize; // 產生新的tid並設定 tid = nextThreadID(); } public long getId() { return tid; }
上面的原始碼中有一個stackSize
的引數,這個一般不會使用,其具體請參考javadoc.
預設執行緒名:"Thread-" + nextThreadNum()
:
/* For autonumbering anonymous threads. */ private static int threadInitNumber; // 同步方法,保證tid的唯一性和連續性 private static synchronized int nextThreadNum() { return threadInitNumber++; } // 執行緒名可以被修改 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; }
ThreadGroup:
《java程式設計思想》有云:把ThreadGroup
當做是一次不成功的嘗試即可,不用理會
public final ThreadGroup getThreadGroup() {
return group;
}
Thread類預設的toString()中有使用其ThreadGroup
:
public String toString() { ThreadGroup group = getThreadGroup(); if (group != null) { return "Thread[" + getName() + "," + getPriority() + "," + group.getName() + "]"; } else { return "Thread[" + getName() + "," + getPriority() + "," + "" + "]"; } }
守護執行緒:
具體參考:Java 守護執行緒概述
示例:Daemon.java
/**
* Marks this thread as either a {@linkplain #isDaemon daemon} thread
* or a user thread. The Java Virtual Machine exits when the only
* threads running are all daemon threads.
* <p> This method must be invoked before the thread is started.
*/
public final void setDaemon(boolean on) {
checkAccess();
// 只有在執行緒開始前設定才有效
if (isAlive()) {
throw new IllegalThreadStateException();
}
daemon = on;
}
public final boolean isDaemon() {
return daemon;
}
// 返回當前執行緒是否還活著
// start()後且還沒有死亡的執行緒均視為活著的執行緒
public final native boolean isAlive();
執行緒優先順序和執行緒狀態:
構造時如果不指定,預設執行緒優先順序就是NORM_PRIORITY
public final static int MIN_PRIORITY = 1;
public final static int NORM_PRIORITY = 5;
public final static int MAX_PRIORITY = 10;
public final void setPriority(int newPriority) {
ThreadGroup g;
checkAccess();
// 優先順序範圍 1~10
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;
}
private native void setPriority0(int newPriority);
/**
* A thread state. A thread can be in one of the following states:
* NEW:A thread that has not yet started is in this state.
* RUNNABLE:A thread executing in the Java virtual machine is in this state.
* BLOCKED:A thread that is blocked waiting for a monitor lock is in this state.
* WAITING:A thread that is waiting indefinitely for another thread to
* perform a particular action is in this state.
* TIMED_WAITING:A thread that is waiting for another thread to perform an action
* for up to a specified waiting time is in this state.
* TERMINATED:A thread that has exited is in this state.
* A thread can be in only one state at a given point in time.
* These states are virtual machine states which do not reflect
* any operating system thread states.
* @since 1.5
*/
public enum State {
// 建立後,但是沒有start(),呼叫了start()後,執行緒才算準備就緒,可以執行(RUNNABLE)
NEW,
// 正在執行或正在等待作業系統排程
RUNNABLE,
// 執行緒正在等待監視器鎖
// 正在synchronized塊/方法上等待獲取鎖,或者呼叫了Object.wait(),等待重新獲得鎖進入同步塊
BLOCKED,
// 呼叫Object.wait(),Thread.join()或LockSupport.park()會進入該狀態,注意這裡的呼叫均為沒有設定超時,
// 執行緒正在等待其他執行緒進行特定操作,比如,呼叫了Object.wait()的執行緒在另一個執行緒呼叫Object.notify()/Object.notifyAll()
// 呼叫了Thread.join()的執行緒在等待指定執行緒停止,join()的內部實現方式也是Object.wait(),只不過其Object就是執行緒物件本身
WAITING,
// 呼叫Thread.sleep(),Object.wait(long),Thread.join(long),
// LockSupport.parkNanos(long),LockSupport.parkUntil(long)會進入該狀態,
// 注意,這裡的呼叫均設定了超時
TIMED_WAITING,
// 執行緒執行完成,退出
TERMINATED;
}
// @since 1.5
public State getState() {
// get current thread state
return sun.misc.VM.toThreadState(threadStatus);
}
這裡關於執行緒狀態需要特別注意,在網上有很多部落格和書籍對執行緒狀態進行講解,其中很大一部分是錯誤的,對於BLOCKED,WAITING和TIMED_WAITING有所誤解,認為一個執行緒在被從Object.wait()中被喚醒時,會立即進入Runnable狀態,其實不是的:
一個執行緒在被從Object.wait()中被喚醒時,會立即進入BLOCKED狀態,這時其並沒有獲得鎖,只是被喚醒了,再次開始對Object的監視器鎖進行競爭;只有在其競爭獲得鎖之後才會進入RUNNABLE狀態.
在理解java執行緒狀態時,建議直接看Thread.State的註釋,就看英文版本,最貼切,沒有雜質,也最正確,其他的所有書上的講解似乎都有些偏頗
todo:
執行緒狀態示例:ThreadState.java
執行緒優先順序示例:Priority.java
關於wait()/notify()具體相關,請參考其他相關部落格;
run():
如果是構造Thread
物件的時候,傳入了該物件預期執行的任務----Runnable
物件時,執行該任務,否則,什麼都不做,當然,可以通過整合Thread類,重寫run(),來修改其行為:
/* What will be run. */
private Runnable target;
@Override
public void run() {
if (target != null) {
target.run();
}
}
執行緒啟動:
呼叫start()與呼叫run()的區別:懶得說
/* Java thread status for tools,
* initialized to indicate thread 'not yet started'
*/
private volatile int threadStatus = 0;
// 啟動執行緒,JVM會呼叫當前Thread物件的run()
// 同步方法
public synchronized void start() {
// A zero status value corresponds to state "NEW".
// 如果呼叫時不是線上程狀態不是NEW,則丟擲IllegalThreadStateException
if (threadStatus != 0)
throw new IllegalThreadStateException();
/* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented. */
group.add(this);
boolean started = false;
try {
// 通過start0()來實現執行緒啟動
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
private native void start0();
執行緒打斷:
/* The object in which this thread is blocked in an interruptible I/O
* operation, if any. The blocker's interrupt method should be invoked
* after setting this thread's interrupt status.
*/
private volatile Interruptible blocker;
private final Object blockerLock = new Object();
/* Set the blocker field; invoked via sun.misc.SharedSecrets from java.nio code
*/
void blockedOn(Interruptible b) {
synchronized (blockerLock) {
blocker = b;
}
}
/**
* 打斷當前執行執行緒
* 如果當前執行緒阻塞在Object.wait(),Thread.join(),Thread.sleep()上,
* 那麼該執行緒會收到InterruptedException,且執行緒的打斷標誌會被清除;
* 如果當前執行緒阻塞在InterruptibleChannel上,那麼該InterruptibleChannel
* 會被關閉,執行緒的打斷標誌會被置位,且當前執行緒會收到ClosedByInterruptException;
* 如果當前執行緒阻塞在Selector上,那麼該Selector的selection操作將會立即返回一個非0的結果,
* 且Selector.wakeup()會被呼叫,執行緒的打斷標誌會被置位,
* 如果上述情況均不存在,將當前執行緒的打斷標誌置位
* 打斷一個isAlive()返回false的執行緒沒有效果,isInterrupted()仍然會返回false;
*/
public void interrupt() {
if (this != Thread.currentThread())
checkAccess();
synchronized (blockerLock) {
Interruptible b = blocker;
// 在Interruptible上阻塞
if (b != null) {
interrupt0(); // Just to set the interrupt flag
b.interrupt(this);
return;
}
}
interrupt0();
}
private native void interrupt0();
/**
* 返回執行緒是否被打斷(打斷標誌是否被置位)
* 傳入的引數決定是否該方法是否會清除終端標誌位
*/
private native boolean isInterrupted(boolean ClearInterrupted);
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
public boolean isInterrupted() {
return isInterrupted(false);
}
關於isInterrupted()和interrupted()的區別,上述源碼錶現得很明顯
而且,也體現了NIO的可中斷中斷實現方式
注意:interrupt()不能中斷執行阻塞IO操作的執行緒.
執行緒的禮讓—— yield() sleep() join():
關於Thread.sleep()和Object.wait()的區別:參考連結
示例:Yield.java
/**
* 暗示排程器讓出當前執行緒的執行時間片,排程器可以選擇忽略該暗示;
* 該方法在用來除錯和測試時可能很有用,可以用來重現需要特殊條件才能復現的bug;
* 也可以用來進行併發優化等;
*/
public static native void yield();
/**
* 當前執行執行緒休眠指定毫秒在休眠期間,不釋放任何當前執行緒持有的鎖;
*/
public static native void sleep(long millis) throws InterruptedException;
/**
* 當前執行執行緒休眠指定毫秒在休眠期間,不釋放任何當前執行緒持有的鎖;
* 如果當前被打斷(該方法呼叫前或該方法呼叫時),丟擲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");
}
// 納秒最後還是轉換成了毫秒233333
// 可能是考慮都有些
if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
millis++;
}
sleep(millis);
}
/**
* 當前執行執行緒等待指定執行緒(也就是該呼叫發生的Thread物件)死後再繼續執行;
* 可以設定超時,如果設定超時為0,則為不設定超時;
* 執行緒結束時(terminate),將會呼叫自身的notifyAll(),喚醒在該Thread物件上wait()的方法;
* 如果該執行緒被打斷,該方法將丟擲InterruptedException,並將打斷標誌位清除
*/
// 同步方法,同步當前Thread物件,所以才能在其內部呼叫wait()
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
// 使用isAlive()和wait()的迴圈實現
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
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 >= 500000 || (nanos != 0 && millis == 0)) {
millis++;
}
join(millis);
}
public final void join() throws InterruptedException {
join(0);
}
/**
* This method is called by the system to give a Thread
* a chance to clean up before it actually exits.
*/
private void exit() {
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;
}
被遺棄的方法——suspend() resume() stop():
關於這些方法被遺棄的原因,具體參考:Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?
/**
* 掛起當前執行緒
* 棄用原因:容易導致死鎖
*/
@Deprecated
public final void suspend() {
checkAccess();
suspend0();
}
/**
* 從suspend()中恢復執行緒執行
* 棄用原因:容易導致死鎖
*/
@Deprecated
public final void resume() {
checkAccess();
resume0();
}
/**
* 強制執行緒停止執行;
* 通過丟擲一個ThreadDeath的方式來停止執行緒;
* 廢棄原因:stop()會師範所有已持有的鎖的監視器,如果存在之前被這些監視器保護的物件處於一個不連續
* 的狀態(inconsistent state),這些被損壞的物件將會對其他執行緒可見,出現不可預期的行為;
*/
@Deprecated
public final void stop() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
checkAccess();
if (this != Thread.currentThread()) {
security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
}
}
// A zero status value corresponds to "NEW", it can't change to
// not-NEW because we hold the lock.
if (threadStatus != 0) {
resume(); // Wake up thread if it was suspended; no-op otherwise
}
// The VM can handle all thread states
stop0(new ThreadDeath());
}
ThreadLocal:
在Thread類中有兩個與ThreadLocal相關的成員變數
具體有關ThreadLocal,請參考:
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
/*
* InheritableThreadLocal values pertaining to this thread. This map is
* maintained by the InheritableThreadLocal class.
*/
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
ClassLoader:
關於ClassLoader,我暫時知道的也不多,先知道這個,以後有機會專門研究一下ClassLoader:
/* The context ClassLoader for this thread */
private ClassLoader contextClassLoader;
/**
* 當前執行緒的ClassLoader,預設建立時是父執行緒的ClassLoader
* @return the context ClassLoader for this Thread, or {@code null}
* indicating the system class loader (or, failing that, the
* bootstrap class loader)
* @since 1.2
*/
@CallerSensitive
public ClassLoader getContextClassLoader() {
if (contextClassLoader == null)
return null;
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
ClassLoader.checkClassLoaderPermission(contextClassLoader,Reflection.getCallerClass());
}
return contextClassLoader;
}
/**
* @param cl
* the context ClassLoader for this Thread, or null indicating the
* system class loader (or, failing that, the bootstrap class loader)
* @since 1.2
*/
public void setContextClassLoader(ClassLoader cl) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("setContextClassLoader"));
}
contextClassLoader = cl;
}
執行緒棧軌跡:
// 特殊程式設計技巧
private static final StackTraceElement[] EMPTY_STACK_TRACE
= new StackTraceElement[0];
private native static StackTraceElement[][] dumpThreads(Thread[] threads);
private native static Thread[] getThreads();
// 列印當前執行緒的棧軌跡(StackTrace),通過新建一個異常的方式實現
// 注意:這是一個靜態方法
public static void dumpStack() {
new Exception("Stack trace").printStackTrace();
}
/**
* 獲得棧軌跡,返回的是一個數組
* 陣列的第0個棧軌跡為最近呼叫的棧軌跡
* @since 1.5
*/
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);
}
// 不是活著的,返回的棧軌跡長度為0
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) {
// 這樣就不會返回null,呼叫者也無需判斷null了
stackTrace = EMPTY_STACK_TRACE;
}
return stackTrace;
} else {
// Don't need JVM help for current thread
return (new Exception()).getStackTrace();
}
}
/**
* 返回所有執行緒的棧軌跡
* @since 1.5
*/
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;
}
UncaughtExceptionHandler:
示例:UncaughtExceptionHandlerEx.java
// null unless explicitly set
private volatile UncaughtExceptionHandler uncaughtExceptionHandler;
// null unless explicitly set
private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler;
/**
* 設定UncaughtExceptionHandler,該設定對所有執行緒有效
* 如果自身沒有設定,則交給其執行緒組的UncaughtExceptionHandler處理,如果再沒有,
* 則交給預設的的UncaughtExceptionHandler處理,也即這裡設定的UncaughtExceptionHandler處理
* 注意這裡的設定不應該設定為執行緒的執行緒組,這樣的設定會造成死迴圈
* @since 1.5
*/
public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("setDefaultUncaughtExceptionHandler"));
}
defaultUncaughtExceptionHandler = eh;
}
/**
* 返回預設的UncaughtExceptionHandler,該UncaughtExceptionHandler對所有執行緒有效
* 這是一個靜態方法
* @since 1.5
*/
public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler(){
return defaultUncaughtExceptionHandler;
}
/**
* 返回該執行緒的UncaughtExceptionHandler,如果沒有,返回該執行緒的執行緒組
* ThreadGroup本身實現了UncaughtExceptionHandler介面
* @since 1.5
*/
public UncaughtExceptionHandler getUncaughtExceptionHandler() {
return uncaughtExceptionHandler != null ?
uncaughtExceptionHandler : group;
}
/**
* 設定該執行緒的UncaughtExceptionHandler
*/
public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
checkAccess();
uncaughtExceptionHandler = eh;
}
/**
* uncaught exception 分發給UncaughtExceptionHandler
* 該方法被JVM呼叫
*/
private void dispatchUncaughtException(Throwable e) {
getUncaughtExceptionHandler().uncaughtException(this, e);
}
其他:
// 返回當前語句執行的執行緒
public static native Thread currentThread();
// 不能克隆執行緒
@Override
protected Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
/**
* 返回該執行緒是否持有指定物件的監視器鎖
* @since 1.4
*/
public static native boolean holdsLock(Object obj);