Java-多线程-线程状态
1 简介
Java线程并不是和Linux线程完全对等的,每个Java线程拥有NEW(新建)、RUNNABLE(就绪)、BLOCKED(阻塞)、WAITING(等待)、TIMED WAITING(计时等待)、TERMINATED(终止)。
Java线程调度属于抢占式调度,线程竞争CPU时间分片来执行,一个线程运行几十毫秒中就处于RUNNING状态,而时间片用完了被剥夺CPU资源又处于READY状态了,等待下次调度。
2 线程状态
/**
* 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;
}
-
NEW(新建)
使用new Thread(new Runnable)
类或其子类建立一个线程对象后,该线程对象就处于新建状态。此时线程还未执行,一般是在构造方法中做一些初始化工作。
NEW状态的线程只能在
thread.start()
方法之后转为RUNNABLE状态。 -
RUNNABLE(就绪)
NEW状态的线程调用了thread.start()
方法之后,该线程就进入RUNNABLE状态,等待JVM里线程调度器的调度,此时处于READY就绪状态。当获得CPU时间片后,线程开始执行,线程处于RUNNING运行状态。时间片用完后,线程被剥夺运行资格,等待下一次运行,又变为就绪状态。也就是说,此状态下不能保证线程是就绪还是正在运行。
-
BLOCKED(阻塞)
RUNNABLE状态线程申请被其他线程持有的对象锁,此时就转为BLOCKED
状态,此时线程不运行任何代码且消耗最少的资源,直到线程调度器重新激活运行该线程。当其他线程释放该对象锁后,如果本线程竞争到了对象锁,就转回
RUNNABLE
状态。 -
WAITING(无期限等待)
如果一个线程A等待另一个线程给与调度器一个条件时,线程A进入WAITING
状态,等待被其他线程notify唤醒。如调用
Object.wait
、Thread.join
、java.util.concurrent
中的Lock或Condition等。条件发生后,就转回
RUNNABLE
状态。(如果是wait方法进入的等待状态,被notify唤醒后进入对象锁同步队列重新竞争锁,竞争到了就进入RUNNABLE状态,竞争失败就进入BLOCKED状态) -
TIMED WAITING(计时等待)
以上方法有一些带有时间参数的重载方法(如Object.wait
、Thread.join
、java.util.concurrent
中的Lock.tryLock、Condition.await),就会进入TIMED WAITING
状态条件发生后,就转回`RUNNABLE`状态(如果是wait方法进入的等待状态,被notify唤醒后进入对象锁同步队列重新竞争锁,竞争到了就进入RUNNABLE状态,竞争失败就进入BLOCKED状态)。
-
TERMINATED(终止)
线程run方法结束或抛出了未捕获的异常导致结束。在一个TERMINATED的线程上调用start()方法会抛出
java.lang.IllegalThreadStateException
异常。
3 相关方法
-
Thread.sleep(long millis)
由当前线程调用此方法,调用后进入TIMED_WAITING
状态,但不释放对象锁。millis期满后线程自动唤醒进入RUNNABLE状态。 -
Thread.yield(),
由当前线程调用此方法,给CPU提示表示当前线程愿意放弃获取的CPU时间片(调度器可忽略该提示),但不释放对象锁。如果成功释放时间片则该线程由运行状态变为就绪状态,由调度器再次选择线程进行调度执行。- Sleep对比Yield
主要是使用场景不同。Sleep主要用来指定睡眠时间让出CPU,并在时间到后再被系统分配CPU资源,进行调度执行;而Yield是用来主动释放CPU给其他线程执行,但无法精确控制是否释放。
- Sleep对比Yield
-
t.join()/t.join(long millis),
join方法主要用来等待其他线程运行结束,再继续运行自己的线程代码。当前线程里调用其它线程t的join方法,当前线程进入
WAITING
/TIMED_WAITING
状态,当前线程不会释放已经持有的对象锁。等到线程t执行完毕或者millis时间到,当前线程重新进入
RUNNABLE
状态。 -
obj.wait()
当前线程调用对象的wait()方法,当前线程会释放该对象锁,并进入等待队列等待其他竞争到锁的线程执行完后唤醒,重新进入等待队列进行锁竞争,竞争成功后才会从wait方法返回。注意这个wait方法只会让该线程释放当前Object的对象锁,而不会放弃拥有的其他对象锁!
-
obj.wait(mills)
当前线程调用对象的wait()方法,当前线程会释放该对象锁,并进入等待队列等待其他竞争到锁的线程执行完后唤醒或时间耗尽,重新进入等待队列进行锁竞争,竞争成功后才会从wait方法返回。注意这个wait方法只会让该线程释放当前Object的对象锁,而不会放弃拥有的其他对象锁!
-
obj.notify()
该方法用来任意唤醒一个在对象锁的等待集的线程(其实看了源码会发现不是任意的,而是一个WaitQueue,FIFO)。 -
obj.notifyAll()
唤醒在此对象Monitor上等待的所有线程。
4 线程优先级
很多操作系统都提供线程优先级的概念,但是由于平台特性的问题,Java中的线程优先级和不同平台中系统线程优先级并不匹配,所以Java线程优先级可以仅仅理解为“建议优先级”,通俗来说就是java.lang.Thread#setPriority(int newPriority)
并不一定生效,有可能Java线程的优先级会被系统自行改变。