Java线程状态
Java 线程的6个状态
// Thread.State 源码
public enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
}
每个线程在时间点只能属于一种状态
NEW
线程尚未启动。即还未调用 start
方法
Thread thread = new Thread();
System.out.println(thread.getState());
输出NEW
引申问题
服务调用一个线程
start
可以吗?线程执行完毕,再调用
start
方法可以吗?
大难是都不可以,start 会判断 线程 的 threadStatus ,只要 != 0 会抛出异常。调用一次 start
后,threadStatus 的值会改变。
RUNNABLE
线程正在运行。可能再JVM中运行,也可能再等待CPU分配资源。
BLOCKED
阻塞状态。等待锁(monitor lock)的释放进入同步区(synchronized block/method)。
WAITING
等待状态。处于改状态下的线程需要其他线程唤醒(Object.notify() or Object.notifyAll() )
进入该状态的三种方法:
- Object.wait with no timeout 使当前线程处于等待状态
- Thread.join with no timeout 底层调用的是 Object.wait
- LockSupport.park 禁止线程进行线程调度
TIMED_WAITING
带超时时间的等待状态。线程等待一个具体的事件,到期后自动唤醒。
进入改状态的方法:
- Thread.sleep
- Object.wait with timeout
- Thread.join with timeout
- LockSupport.parkNanos
- LockSupport.parkUntil
TERMINATED
线程运行完毕。
状态转换
线程正常流程
NEW -> RUNNABLE-> TERMIATED
BLOCKED 与 RUNNABLE
线程进入 BLOCKED 状态是因为等待锁的释放。
下面有两个线程a和b,a获得了锁且暂未释放,此时b处于 BLOCKED 状态。
@Test
public void blockedTest() throws InterruptedException {
Thread a = new Thread(this::testMethod, "a");
Thread b = new Thread(this::testMethod, "b");
a.start();
Thread.sleep(100);
b.start();
Thread.sleep(100);
System.out.println(a.getName() + ":" + a.getState()); // a:RUNNABLE
System.out.println(b.getName() + ":" + b.getState()); // b:BLOCKED
}
// 同步方法争夺锁
private synchronized void testMethod() {
for (; ; ) {
}
}
要加入一些延迟,因为b 一开始也是 RUNNABLE状态。
a,b 线程启动后,a 线程先进入到 synchronized 块,拿到对象锁。
b线程需要等待对象锁释放,就进入到了 BLOCKED 状态。
WAITING 与 RUNNABLE
- Object.wait()
调用 wait 方法 前线程必须持有对象锁。
调用 wait
方法时,会释放当前的锁,直到其他线程调用notify/notifyAll
唤醒等待锁的线程。
- Thread.join
当前线程 等待 调用join方法的线程执行完毕。当前线程进入WAITING 状态
public void blockedTest() { a.start(); a.join();//a RUNNABLE 当前线程WAITING
//a执行完毕 a TERMINATED 当前线程 RUNNABLE
}
TIMED_WAITING 与 RUNNABLE
与 WAITING 与 RUNNABLE 转换类似,只是加上了等待超时的时间。
- Thread.sleep
当前线程睡眠指定时间。并不会释放锁,时间到后,线程进入 RUNNABLE 状态。
线程中断
一些情况下,我们在线程启动后不想让他继续执行,就需要中断线程。Java 还没有安全直接的方法来停止线程,但 Java 提供了线程中断机制里处理需要中断线程的情况。
线程中断机制是一种协作机制。需要注意,通过中断操作并不能直接终止一个线程,而是通知需要被中断的线程自行处理。
- Thread.interrupt 中断线程,不会立即停止线程,设置线程的中断状态为 true
- Thread.currentThread().isInterrupted() 测试当前线程是否被中断。调用后会重置线程中断状态为false。
- Thread.isInterrupted():测试当前线程是否被中断。与上面方法区别是不会影响线程的中断状态。
线程被通知中断后,中断状态设为true,当时被中断线程如何处理,视自己而定,可以再合适的时候响应中断,也可以完全不处理。
如下,线程自己判断中断状态来跳出循环
@Test
public void test() throws InterruptedException {
Thread thread = new Thread(() -> {
for (; ; ) {
System.out.println(System.currentTimeMillis());
if (Thread.currentThread().interrupted()) {
return;
}
}
});
thread.start();
thread.interrupt();
thread.join();
}