1. 程式人生 > >Thread類原始碼解析

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當做是一次不成功的嘗試即可,不用理會

示例:ThreadGroupTest.java

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();

執行緒優先順序和執行緒狀態:

Java 執行緒狀態與優先順序相關的知識題目

示例:ThreadState.java

Priority.java

構造時如果不指定,預設執行緒優先順序就是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();

執行緒打斷:

示例:Interrupted.java

/* 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

Join.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():

示例:Deprecated.java

關於這些方法被遺棄的原因,具體參考: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

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);