Java 线程状态转换


我们要知道Java中的线程状态转换,得先知道它有哪些状态,然后在研究它们在什么情况下才会转换。我们先看一下Java源码中是如何定义线程状态的,位置在
java.lang.Thread 类中的内部枚举类 public enum State 中,大概在1742行

/**
     * A thread state.  A thread can be in one of the following states:
     * <ul>
     * <li>{@link #NEW}<br>
     *     A thread that has not yet started is in this state.
     *     </li>
     * <li>{@link #RUNNABLE}<br>
     *     A thread executing in the Java virtual machine is in this state.
     *     </li>
     * <li>{@link #BLOCKED}<br>
     *     A thread that is blocked waiting for a monitor lock
     *     is in this state.
     *     </li>
     * <li>{@link #WAITING}<br>
     *     A thread that is waiting indefinitely for another thread to
     *     perform a particular action is in this state.
     *     </li>
     * <li>{@link #TIMED_WAITING}<br>
     *     A thread that is waiting for another thread to perform an action
     *     for up to a specified waiting time is in this state.
     *     </li>
     * <li>{@link #TERMINATED}<br>
     *     A thread that has exited is in this state.
     *     </li>
     * </ul>
     *
     * <p>
     * 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
     * @see #getState
     */
    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:
         * <ul>
         *   <li>{@link Object#wait() Object.wait} with no timeout</li>
         *   <li>{@link #join() Thread.join} with no timeout</li>
         *   <li>{@link LockSupport#park() LockSupport.park}</li>
         * </ul>
         *
         * <p>A thread in the waiting state is waiting for another thread to
         * perform a particular action.
         *
         * For example, a thread that has called <tt>Object.wait()</tt>
         * on an object is waiting for another thread to call
         * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
         * that object. A thread that has called <tt>Thread.join()</tt>
         * 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:
         * <ul>
         *   <li>{@link #sleep Thread.sleep}</li>
         *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
         *   <li>{@link #join(long) Thread.join} with timeout</li>
         *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
         *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
         * </ul>
         */
        TIMED_WAITING,

        /**
         * Thread state for a terminated thread.
         * The thread has completed execution.
         */
        TERMINATED;
    }

通过源码我们知道,Java是在1.5版本中才加入对线程支持的,也就是说一开始JDK其实是不支持多线程编程的。那源码中定义了6中状态分别是,

NEW: 新建
RUNNABLE: 就绪
BLOCK: 阻塞
WAITING: 等待
TIMED_WATING: 限时等待
TERMINATED: 终止

那为什么要区分这么多种状态呢? 注释都已经写得清清楚楚了。

NEW

/**
* Thread state for a thread which has not yet started.
*/
还没有开始的线程所处的状态

每一个线程,在堆内存中都有一个对应的Thread对象。Thread t = new Thread();当刚刚在堆内存中创建Thread对象,还没有调用t.start()方法之前,线程就处在NEW状态。在这个状态上,线程与普通的java对象没有什么区别,就仅仅是一个堆内存中的对象。

RUNNABLE

/**
* 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.
*/
线程在Java虚拟机中的状态,再该状态下,线程正在等待操作系统的处理器给他分配资源

对应 t.start() 调用的时候或者运行中的线程自己调用yield方法礼让一下的时候或者当前线程的cpu时间轮片到了出发了cpu中断,该线程响应中断后会改变状态,此时还会引起上下文的切换。

BLOCK

/**
* 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}.
*/
该状态下当前线程在等待一把锁。当遇到 synchronized 的时候就会处于该状态 或者调用一个对象的wait方法后被其他线程唤醒再次尝试获取 synchronized 锁的时候获取失败会再次进入该状态。

可见阻塞状态一定是跟锁有关的,也就是同步的时候,是因为线程获取不到锁才进入的状态,醒来的第一件事情一定是获取锁。获取到锁执行同步代码,获取不到锁就继续阻塞,直到下次醒来后继续执行。所以这个地方等待的是锁的释放。

WAITING,

  • {@link Object#wait() Object.wait} with no timeout
    当调用不加时间的wait方法的时候。注意这里要想调用wait方法一定得先获取到对象对应的锁。获取不到锁进入阻塞状态,获取到锁后才调用wait方法,这时候直接进入WAITING状态。这个地方等待的是有人来唤醒(调用notify或notifyAll)
  • {@link #join() Thread.join} with no timeout
    把一个线程加到当前线程的执行流程中,也就是在join那个时间点等待执行线程的完成,完成后才继续执行,所以这是时候当前线程是处于WATING状态的,这个地方等待的是另一个线程执行完成后在唤醒。(其原理是先把当前线程挂起WATING,并把线程id传递给另一个线程,另一线程执行完成后,根据线程ID吧当前线程的状态改为RUNABLE。然后当前线程等待cpu调度)
    Join 方法:本质上还是根据wait方法实现的。分析join源码发现join方法本身是使用了synchronized修饰符的。是加在方法上面的,意味着。 获取了当前对象的锁,然后继续发现里面的代码调用了wait。意味着我们先锁,再释放,等待唤醒,什么情况下被唤醒呢?执行结束的时候。调用wait之后一定阻塞的是当前线程,及时wait的对象是一个线程。
  • {@link LockSupport#park() LockSupport.park}
    可见等待状态其实与锁无关,它的唤醒一定是另一个线程完成某件事情后主动去唤醒(所谓唤醒,其实就是把状态改为RUNNABLE)

TIMED_WAITING

  • {@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_WATTING 状态一定是和时间有关,等时间到了,自动出发唤醒(其实现原理是,先把线程ID 放到一个队列中,然后每隔时钟周期都检查是不是有线程到时间了,到了就把状态改为RUNABLE)。这个定时唤醒是系统时钟搞得鬼,系统时钟也是独立运行的时钟,可以像它上面注册时钟事件,当时间到了之后,就会发起中断,以唤醒进程。而且cpu一定会响应的。

TERMINATED
这个状态没有什么多说的,当线程运行结束的时候或者异常的时候就会别设置为该状态。已经是终态了。


评论