Thread 类源码阅读

本想看看 AQS 相关代码,但是返现 Thread 状态与通信内容记不清楚,就先看下 Thread 类源码。
Thread 类的源码简单,因为主要逻辑都是 native 方法中。本文与其说是源码阅读,不如说是Java Doc 阅读。

构造函数

image.png

构造代码较简单,忽略,逻辑全部在 init 方法中。

/**
 * Initializes a Thread.
 *
 * @param g the Thread group
 * @param target the object whose run() method gets called
 * @param name the name of the new Thread
 * @param stackSize the desired stack size for the new thread, or
 *        zero to indicate that this parameter is to be ignored.
 * @param acc the AccessControlContext to inherit, or
 *            AccessController.getContext() if null
 * @param inheritThreadLocals if {@code true}, inherit initial values for
 *            inheritable thread-locals from the constructing thread
 */
private void init(ThreadGroup g, Runnable target, String name,
                  long stackSize, AccessControlContext acc,
                  boolean inheritThreadLocals) {
    if (name == null) {
        throw new NullPointerException("name cannot be null");
    }

    this.name = name;

    Thread parent = currentThread();
    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;

    /* Set thread ID */
    tid = nextThreadID();
}

逐一介绍 Thread 类的成员变量

private volatile String name; // 线程名称,可通过构造指定
private int priority; // Java 线程的优先级定义为从 1 到 10 的等级,默认为 5
private Thread threadQ; //
private long eetop; // 
private boolean single_step; // 
private boolean daemon = false; // 守护线程
private boolean stillborn = false; 
private Runnable target; // Runnable 对象
private ThreadGroup group; // 线程组
private ClassLoader contextClassLoader;
private AccessControlContext inheritedAccessControlContext;
private static int threadInitNumber;
ThreadLocalMap threadLocals = null; // 线程本地变量Map, 由 ThreadLocal 持有
ThreadLocalMap inheritableThreadLocals = null; // 可继承的线程本地变量,由 InheritableThreadLocal 持有
private long stackSize; // 线程要求的栈深度,有些VM会忽略,暂不深究
private long nativeParkEventPointer;
private long tid; // 线程ID
private static long threadSeqNumber; // 用户生成线程ID,计数用
private volatile int threadStatus = 0; // 线程状态,下文由单独描述
volatile Object parkBlocker;
private volatile Interruptible blocker;
private final Object blockerLock = new Object();
public static final int MIN_PRIORITY = 1;
public static final int NORM_PRIORITY = 5;
public static final int MAX_PRIORITY = 10;
private static final StackTraceElement[] EMPTY_STACK_TRACE;
private static final RuntimePermission SUBCLASS_IMPLEMENTATION_PERMISSION;
private volatile Thread.UncaughtExceptionHandler uncaughtExceptionHandler;
private static volatile Thread.UncaughtExceptionHandler defaultUncaughtExceptionHandler;
@Contended("tlr")
long threadLocalRandomSeed;
@Contended("tlr")
int threadLocalRandomProbe;
@Contended("tlr")
int threadLocalRandomSecondarySeed;

线程状态, 注释异常详细,不再赘述。

public enum State {
    /**
     * Thread state for a thread which has not yet started.
     */
    NEW,

    /**
     * Thread state for a runnable thread.  A thread in the runnable
     * state is executing in the Java virtual machine but it may
     * be waiting for other resources from the operating system
     * such as processor.
     */
    RUNNABLE,

    /**
     * Thread state for a thread blocked waiting for a monitor lock.
     * A thread in the blocked state is waiting for a monitor lock
     * to enter a synchronized block/method or
     * reenter a synchronized block/method after calling
     * {@link Object#wait() Object.wait}.
     */
    BLOCKED,

    /**
     * Thread state for a waiting thread.
     * A thread is in the waiting state due to calling one of the
     * following methods:
     * 
    *
  • {@link Object#wait() Object.wait} with no timeout
  • *
  • {@link #join() Thread.join} with no timeout
  • *
  • {@link LockSupport#park() LockSupport.park}
  • *
* *

A thread in the waiting state is waiting for another thread to * perform a particular action. * * For example, a thread that has called Object.wait() * on an object is waiting for another thread to call * Object.notify() or Object.notifyAll() on * that object. A thread that has called Thread.join() * is waiting for a specified thread to terminate. */ WAITING, /** * Thread state for a waiting thread with a specified waiting time. * A thread is in the timed waiting state due to calling one of * the following methods with a specified positive waiting time: *

    *
  • {@link #sleep Thread.sleep}
  • *
  • {@link Object#wait(long) Object.wait} with timeout
  • *
  • {@link #join(long) Thread.join} with timeout
  • *
  • {@link LockSupport#parkNanos LockSupport.parkNanos}
  • *
  • {@link LockSupport#parkUntil LockSupport.parkUntil}
  • *
*/ TIMED_WAITING, /** * Thread state for a terminated thread. * The thread has completed execution. */ TERMINATED; }

在介绍完 Thread 类的各个方法之后,再介绍线程状态转变的逻辑。

Thread 主要方法介绍

currentThread

public static native Thread currentThread(); // 获取当前线程

yield

public static native void yield(); // 暗示调度器让出当前线程的执行时间片,调度器可以选择忽略该暗示

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 >= 500000 || (nanos != 0 && millis == 0)) {
        millis++;
    }

    sleep(millis);
}

interrupted

/**
 * Tests whether the current thread has been interrupted.  The
 * interrupted status of the thread is cleared by this method.  In
 * other words, if this method were to be called twice in succession, the
 * second call would return false (unless the current thread were
 * interrupted again, after the first call had cleared its interrupted
 * status and before the second call had examined it).
 * 返回当前线程是否被打断(打断标志是否被置位),会清除中断标志,即第二次调用会返回 false
 *
 * 

A thread interruption ignored because a thread was not alive * at the time of the interrupt will be reflected by this method * returning false. * * @return true if the current thread has been interrupted; * false otherwise. * @see #isInterrupted() * @revised 6.0 */ public static boolean interrupted() { return currentThread().isInterrupted(true); }

dumpStack

/**
 * Prints a stack trace of the current thread to the standard error stream.
 * This method is used only for debugging.
 * 打印当前执行线程的栈信息
 *
 * @see     Throwable#printStackTrace()
 */
public static void dumpStack() {
    new Exception("Stack trace").printStackTrace();
}

以上都是静态方法,正对当前正在运行线程的操作。
下面开始介绍成员方法,针对某一线程的操作。

clone
抛出异常
start

/**
 * Causes this thread to begin execution; the Java Virtual Machine
 * calls the run method of this thread.
 * 触发线程开始执行;JVM 调用该线程的 run 方法
 * 

* The result is that two threads are running concurrently: the * current thread (which returns from the call to the * start method) and the other thread (which executes its * run method). *

* 结果是同时有两个线程是 running 状态, 一个调用 start 方法返回, 一个执行线程的 run 方法 * It is never legal to start a thread more than once. * In particular, a thread may not be restarted once it has completed * execution. * * @exception IllegalThreadStateException if the thread was already * started. * @see #run() * @see #stop() */ public synchronized void start() { /** * This method is not invoked for the main method thread or "system" * group threads created/set up by the VM. Any new functionality added * to this method in the future may have to also be added to the VM. * * A zero status value corresponds to state "NEW". */ // 检查状态必须为 0, 即 NEW 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(); 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();

run

// run 方法,就是运行 target 的 run 方法,不能当作新起一个线程
public void run() {
    if (target != null) {
        target.run();
    }
}

stop
停止线程,方法已经被 @Deprecated 注释,不在详细介绍
interrupt

/**
 * Interrupts this thread.
 * 打断当前执行线程
 *
 * 

Unless the current thread is interrupting itself, which is * always permitted, the {@link #checkAccess() checkAccess} method * of this thread is invoked, which may cause a {@link * SecurityException} to be thrown. * *

If this thread is blocked in an invocation of the {@link * Object#wait() wait()}, {@link Object#wait(long) wait(long)}, or {@link * Object#wait(long, int) wait(long, int)} methods of the {@link Object} * class, or of the {@link #join()}, {@link #join(long)}, {@link * #join(long, int)}, {@link #sleep(long)}, or {@link #sleep(long, int)}, * methods of this class, then its interrupt status will be cleared and it * will receive an {@link InterruptedException}. * 如果这个线程阻塞在Object.wait(),Thread.join(),Thread.sleep()上,那么该线程会收到InterruptedException,且线程的打断标志会被清除; * *

If this thread is blocked in an I/O operation upon an {@link * java.nio.channels.InterruptibleChannel InterruptibleChannel} * then the channel will be closed, the thread's interrupt * status will be set, and the thread will receive a {@link * java.nio.channels.ClosedByInterruptException}. * 如果这个线程阻塞在InterruptibleChannel的IO操作上, 打断标志会被置位,并抛出 ClosedByInterruptException 异常 * *

If this thread is blocked in a {@link java.nio.channels.Selector} * then the thread's interrupt status will be set and it will return * immediately from the selection operation, possibly with a non-zero * value, just as if the selector's {@link * java.nio.channels.Selector#wakeup wakeup} method were invoked. * 如果这个线程阻塞在 Selector 上,打断标志会被置位,那么该Selector的selection操作将会立即返回一个非0的结果, * 且Selector.wakeup()会被调用 * *

If none of the previous conditions hold then this thread's interrupt * status will be set.

* 如果没有以上条件, 打断标志会被置位 * *

Interrupting a thread that is not alive need not have any effect. * 打断一个非活状态( isAlive 方法,返回 false)的线程,无任何影响 * * @throws SecurityException * if the current thread cannot modify this thread * * @revised 6.0 * @spec JSR-51 */ public void interrupt() { if (this != Thread.currentThread()) checkAccess(); synchronized (blockerLock) { Interruptible b = blocker; if (b != null) { interrupt0(); // Just to set the interrupt flag b.interrupt(this); return; } } interrupt0(); }

isInterrupted

/**
 * Tests whether this thread has been interrupted.  The interrupted
 * status of the thread is unaffected by this method.
 * 测试这个线程是否被中断
 *
 * 

A thread interruption ignored because a thread was not alive * at the time of the interrupt will be reflected by this method * returning false. * * @return true if this thread has been interrupted; * false otherwise. * @see #interrupted() * @revised 6.0 */ public boolean isInterrupted() { return isInterrupted(false); } /** * Tests if some Thread has been interrupted. The interrupted state * is reset or not based on the value of ClearInterrupted that is * passed. * 返回线程是否被打断(打断标志是否被置位),传入的参数决定是否该方法是否会清除终端标志位 */ private native boolean isInterrupted(boolean ClearInterrupted);

destroy
被 @Deprecated 修饰,抛出异常
isAlive

/**
 * Tests if this thread is alive. A thread is alive if it has
 * been started and has not yet died.
 * 返回当前线程是否还活着,start()后且还没有死亡的线程均视为活着的线程
 *
 * @return  true if this thread is alive;
 *          false otherwise.
 */
public final native boolean isAlive();

suspend、resume、countStackFrames
被 @Deprecated 修饰
setPriority getPriority

/**
 * Changes the priority of this thread.
 * 修改线程优先级
 * 

* First the checkAccess method of this thread is called * with no arguments. This may result in throwing a * SecurityException. *

* Otherwise, the priority of this thread is set to the smaller of * the specified newPriority and the maximum permitted * priority of the thread's thread group. * * @param newPriority priority to set this thread to * @exception IllegalArgumentException If the priority is not in the * range MIN_PRIORITY to * MAX_PRIORITY. * @exception SecurityException if the current thread cannot modify * this thread. * @see #getPriority * @see #checkAccess() * @see #getThreadGroup() * @see #MAX_PRIORITY * @see #MIN_PRIORITY * @see ThreadGroup#getMaxPriority() */ 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); } } /** * Returns this thread's priority. * 返回线程优先级 * * @return this thread's priority. * @see #setPriority */ public final int getPriority() { return priority; }

setName、getName

/**
 * Changes the name of this thread to be equal to the argument
 * name.
 * 修改线程名称
 * 

* First the checkAccess method of this thread is called * with no arguments. This may result in throwing a * SecurityException. * * @param name the new name for this thread. * @exception SecurityException if the current thread cannot modify this * thread. * @see #getName * @see #checkAccess() */ 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); } } /** * Returns this thread's name. * 获取线程名称 * * @return this thread's name. * @see #setName(String) */ public final String getName() { return name; }

getThreadGroup

/**
 * Returns the thread group to which this thread belongs.
 * This method returns null if this thread has died
 * (been stopped).
 * 返回所属线程组,如果该线程已死,返回null
 *
 * @return  this thread's thread group.
 */
public final ThreadGroup getThreadGroup() {
    return group;
}
/**
 * Returns an estimate of the number of active threads in the current
 * thread's {@linkplain java.lang.ThreadGroup thread group} and its
 * subgroups. Recursively iterates over all subgroups in the current
 * thread's thread group.
 * 返回当前线程所属的线程组及其子线程组的估算的活跃线程数目
 *
 * 

The value returned is only an estimate because the number of * threads may change dynamically while this method traverses internal * data structures, and might be affected by the presence of certain * system threads. This method is intended primarily for debugging * and monitoring purposes. * 返回值是估算的,因为在该方法执行时,活跃线程是在动态变化的 * * @return an estimate of the number of active threads in the current * thread's thread group and in any other thread group that * has the current thread's thread group as an ancestor */ public static int activeCount() { return currentThread().getThreadGroup().activeCount(); }

/**
 * Copies into the specified array every active thread in the current
 * thread's thread group and its subgroups. This method simply
 * invokes the {@link java.lang.ThreadGroup#enumerate(Thread[])}
 * method of the current thread's thread group.
 * 复制当前线程组及其子线程组的活跃线程到数组中
 *
 * 

An application might use the {@linkplain #activeCount activeCount} * method to get an estimate of how big the array should be, however * if the array is too short to hold all the threads, the extra threads * are silently ignored. If it is critical to obtain every active * thread in the current thread's thread group and its subgroups, the * invoker should verify that the returned int value is strictly less * than the length of {@code tarray}. * 如果数组大小不够,会忽略多余的线程 * *

Due to the inherent race condition in this method, it is recommended * that the method only be used for debugging and monitoring purposes. * * @param tarray * an array into which to put the list of threads * * @return the number of threads put into the array * * @throws SecurityException * if {@link java.lang.ThreadGroup#checkAccess} determines that * the current thread cannot access its thread group */ public static int enumerate(Thread tarray[]) { return currentThread().getThreadGroup().enumerate(tarray); }

join

/**
 * Waits at most {@code millis} milliseconds for this thread to
 * die. A timeout of {@code 0} means to wait forever.
 * 最多等待指定毫秒数这个线程死亡,然后继续执行,参数 0 表示永远等待
 *
 * 

This implementation uses a loop of {@code this.wait} calls * conditioned on {@code this.isAlive}. As a thread terminates the * {@code this.notifyAll} method is invoked. It is recommended that * applications not use {@code wait}, {@code notify}, or * {@code notifyAll} on {@code Thread} instances. * 使用 wait 方法和 isAlive 方法循环实现。当线程结束时,会调用自身的 notifyAll 方法。 * * @param millis * the time to wait in milliseconds * * @throws IllegalArgumentException * if the value of {@code millis} is negative * * @throws InterruptedException * if any thread has interrupted the current thread. The * interrupted status of the current thread is * cleared when this exception is thrown. */ // 亮点!亮点!亮点!亮点!同步方法,同步当前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"); } if (millis == 0) { while (isAlive()) { wait(0); } } else { while (isAlive()) { long delay = millis - now; if (delay <= 0) { break; } wait(delay); now = System.currentTimeMillis() - base; } } } /** * Waits at most {@code millis} milliseconds plus * {@code nanos} nanoseconds for this thread to die. * *

This implementation uses a loop of {@code this.wait} calls * conditioned on {@code this.isAlive}. As a thread terminates the * {@code this.notifyAll} method is invoked. It is recommended that * applications not use {@code wait}, {@code notify}, or * {@code notifyAll} on {@code Thread} instances. * * @param millis * the time to wait in milliseconds * * @param nanos * {@code 0-999999} additional nanoseconds to wait * * @throws IllegalArgumentException * if the value of {@code millis} is negative, or the value * of {@code nanos} is not in the range {@code 0-999999} * * @throws InterruptedException * if any thread has interrupted the current thread. The * interrupted status of the current thread is * cleared when this exception is thrown. */ 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); } /** * Waits for this thread to die. * *

An invocation of this method behaves in exactly the same * way as the invocation * *

* {@linkplain #join(long) join}{@code (0)} *
* * @throws InterruptedException * if any thread has interrupted the current thread. The * interrupted status of the current thread is * cleared when this exception is thrown. */ public final void join() throws InterruptedException { join(0); }

setDaemon、isDaemon

/**

 * 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.
 * 标记线程为用户线程或者守护线程
 *
 * 

This method must be invoked before the thread is started. * 该方法必须在 start 方法之前执行 * * @param on * if {@code true}, marks this thread as a daemon thread * * @throws IllegalThreadStateException * if this thread is {@linkplain #isAlive alive} * * @throws SecurityException * if {@link #checkAccess} determines that the current * thread cannot modify this thread */ public final void setDaemon(boolean on) { checkAccess(); if (isAlive()) { throw new IllegalThreadStateException(); } daemon = on; } /** * Tests if this thread is a daemon thread. * 返回是否时守护线程 * * @return true if this thread is a daemon thread; * false otherwise. * @see #setDaemon(boolean) */ public final boolean isDaemon() { return daemon; }

checkAccess

/**
 * Determines if the currently running thread has permission to
 * modify this thread.
 * 判断当前执行线程是否有权限修改这个线程
 * 

* If there is a security manager, its checkAccess method * is called with this thread as its argument. This may result in * throwing a SecurityException. * * @exception SecurityException if the current thread is not allowed to * access this thread. * @see SecurityManager#checkAccess(Thread) */ public final void checkAccess() { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkAccess(this); } }

toString

getContextClassLoader、setContextClassLoader

/**
 * Returns the context ClassLoader for this Thread. The context
 * ClassLoader is provided by the creator of the thread for use
 * by code running in this thread when loading classes and resources.
 * If not {@linkplain #setContextClassLoader set}, the default is the
 * ClassLoader context of the parent Thread. The context ClassLoader of the
 * primordial thread is typically set to the class loader used to load the
 * application.
 * 返回这个线程的上下文类加载器。上下文类加载器有这个线程的创建者提供
 *
 * 

If a security manager is present, and the invoker's class loader is not * {@code null} and is not the same as or an ancestor of the context class * loader, then this method invokes the security manager's {@link * SecurityManager#checkPermission(java.security.Permission) checkPermission} * method with a {@link RuntimePermission RuntimePermission}{@code * ("getClassLoader")} permission to verify that retrieval of the context * class loader is permitted. * * * @return the context ClassLoader for this Thread, or {@code null} * indicating the system class loader (or, failing that, the * bootstrap class loader) * * @throws SecurityException * if the current thread cannot get the context ClassLoader * * @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; } /** * Sets the context ClassLoader for this Thread. The context * ClassLoader can be set when a thread is created, and allows * the creator of the thread to provide the appropriate class loader, * through {@code getContextClassLoader}, to code running in the thread * when loading classes and resources. * 变更类加载器 * *

If a security manager is present, its {@link * SecurityManager#checkPermission(java.security.Permission) checkPermission} * method is invoked with a {@link RuntimePermission RuntimePermission}{@code * ("setContextClassLoader")} permission to see if setting the context * ClassLoader is permitted. * * @param cl * the context ClassLoader for this Thread, or null indicating the * system class loader (or, failing that, the bootstrap class loader) * * @throws SecurityException * if the current thread cannot set the context ClassLoader * * @since 1.2 */ public void setContextClassLoader(ClassLoader cl) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(new RuntimePermission("setContextClassLoader")); } contextClassLoader = cl; }

holdsLock

/**
 * Returns true if and only if the current thread holds the
 * monitor lock on the specified object.
 * 返回是否持有指定对象锁 
 *
 * 

This method is designed to allow a program to assert that * the current thread already holds a specified lock: *

 *     assert Thread.holdsLock(obj);
 * 
* * @param obj the object on which to test lock ownership * @throws NullPointerException if obj is null * @return true if the current thread holds the monitor lock on * the specified object. * @since 1.4 */ public static native boolean holdsLock(Object obj);

简单介绍了 Thread 类的主要方法之后,我们再来看下,线程状态的转换。
上文提到,状态一共有 NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING 和 TERMINATED 六种。状态之间的转换如下:


image.png

你可能感兴趣的:(Thread 类源码阅读)