二、线程状态源码
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;
}
三、线程状态描述
NEW-创建状态
初始创建线程,比如在主线程中用new关键字创建了一个线程对象。仅仅在堆中分配了内存
RUNNABLE-可执行状态
可执行状态,可以说包含了2种情况,线程start后进入此状态。当调用start方法后,系统才会开启一个新的线程来执行用户定义的子任务,在这个过程中,会为相应的线程分配需要的资源。
public synchronized void start()
就绪(ready):在没有获取到CPU调度权(执行时间)时,线程在准备就绪中
运行(running):获取到CPU调度权(执行时间)后,运行程序
yield方法会让线程从运行(running)退回到就绪(ready)
public static native void yield();
调用yield方法会让当前线程交出CPU权限,让CPU去执行其他的线程。它跟sleep方法类似,同样不会释放锁。但是yield不能控制具体的交出CPU的时间,另外,yield方法只能让拥有相同优先级的线程有获取CPU执行时间的机会。
注意:调用yield方法并不会让线程进入阻塞状态,而是让线程重回就绪状态,它只需要等待重新获取CPU执行时间,这一点是和sleep方法不一样的
BLOCKED-阻塞状态
当线程处于运行状态时,试图获得某个对象的同步锁时,如果该对象的同步锁已经被其他的线程占用,JVM就会把这个线程放到这个对象的琐池中。即多个线程同时调用同步方法块或者同步方法时,未能获取锁的线程处理此状态。
TIMED_WAITING-超时等待状态
调用以下方法,会使用线程进入此超时等待状态
//Thread类-休眠(交出CPU执行权限,不会释放锁)
public static native void sleep(long millis) throws InterruptedException
//Thread类-超时等待(内部调用Object#wait方法,交出CPU执行权限,会释放锁)
public final synchronized void join(long millis)throws InterruptedException
//Object类-超时等待(交出CPU执行权限,会释放锁)
public final native void wait(long timeout) throws InterruptedException
//LockSupport类
public static void parkNanos(Object blocker, long nanos)
//LockSupport类
public static void parkUntil(long deadline)
注意:
sleep相当于让线程睡眠,sleep方法不会释放锁,只是交出CPU,让CPU去执行其他的任务。
wait方法会让线程进入阻塞状态,并且会释放线程占有的锁,并交出CPU执行权限。
WAITING-等待状态
调用以下方法进入此状态
//Thread类-一直等待(内部调用Object#wait方法,会释放锁)
public final synchronized void join()throws InterruptedException
//Object类-一直等待(会释放锁)
public final void wait() throws InterruptedException
//LockSupport类
public static void park(Object blocker)
TERMINATED-终止状态
三、上下文切换
对于单核CPU来说(对于多核CPU,此处就理解为一个核),CPU在一个时刻只能运行一个线程,当在运行一个线程的过程中转去运行另外一个线程,这个叫做线程上下文切换(对于进程也是类似)。
由于可能当前线程的任务并没有执行完毕,所以在切换时需要保存线程的运行状态,以便下次重新切换回来时能够继续切换之前的状态运行。举个简单的例子:比如一个线程A正在读取一个文件的内容,正读到文件的一半,此时需要暂停线程A,转去执行线程B,当再次切换回来执行线程A的时候,我们不希望线程A又从文件的开头来读取。
因此需要记录线程A的运行状态,那么会记录哪些数据呢?因为下次恢复时需要知道在这之前当前线程已经执行到哪条指令了,所以需要记录程序计数器的值,另外比如说线程正在进行某个计算的时候被挂起了,那么下次继续执行的时候需要知道之前挂起时变量的值时多少,因此需要记录CPU寄存器的状态。所以一般来说,线程上下文切换过程中会记录程序计数器、CPU寄存器状态等数据。说简单点的:对于线程的上下文切换实际上就是 存储和恢复CPU状态的过程,它使得线程执行能够从中断点恢复执行。 虽然多线程可以使得任务执行的效率得到提升,但是由于在线程切换时同样会带来一定的开销代价,并且多个线程会导致系统资源占用的增加,所以在进行多线程编程时要注意这些因素。
四、方法与CPU执行权限,同步锁,堆内存占用对比
类#方法 | 功能 | cpu执行权限 | 同步锁 | 堆内存 | 备注 |
Object#notify | 通知等待结束 |
| 占有 |
| 只有其所在同步方法/块执行完才释放 |
Object#wait | 对象等待 | 释放 | 释放 |
|
|
Thread#join | 等待 | 释放 | 释放 |
|
|
Thread#sleep | 休眠 | 释放 | 占有 |
|
|
Thread#yield | 放弃当前CPU权限 | 释放 | 占有 |
|
|
Thread#stop | 立即停止线程 | 释放 | 释放 |
| 立即释放同步锁,状态可能不一致 |
Thread#suspend | 暂停线程 | 释放 | 占有 |
| 独占锁,使用不当会死锁 |
Thread#resume | 恢复线程运行 |
|
|
|
|
--------------------------------
引用原文列表:
- 《JAVA多线程编程核心技术》
- Java Thread 的使用