一. 线程的几种状态
1.观察线程的所有状态
线程的状态是一个枚举类型 Thread.state
public static void main(String[] args) {
for (Thread.State state : Thread.State.values()) {
System.out.println(state);
}
}
下面我详细解释一下这几种状态的含义:
2.线程状态的含义
- NEW : Thread 对象被创建出来, 但是内核的PCB还没创建(还没真正的创建线程)
- TERMINATED : 内核的PCB销毁了, 但是Thread对象还在
- RUNNABLE : 就绪状态. (正在CPU上运行 + 在就绪队列中排队)
- TIMED_WAITING : 按照一定的时间, 进行阻塞, sleep.
- WAITING : 特殊的阻塞状态, 调用wait.
- BLOCKED : 等待锁的时候进入的阻塞状态.
3.线程状态和状态转移
从上图来看, 最开始是一个 NEW 状态, 然后进入 RUNNABLE 状态, 也就是线程开始运行了, 再然后运行完了就进入 TERMINATED 状态, 这是主干道, 线程从开始到结束的状态, 然后再 RUNNABLE 过程中可能会产生其他状态, 就是 TIMED_WAITING 和 BLOCKED 和 WAITING, RUNNABLE 可以在这三个状态之间转换, 怎样进入 WAITING 状态呢, 也就是 wait方法和join()不带参数的版本, 要是进入 TIMED_WAITING 状态呢, 就是sleep和join(time)带时间的版本, 而进入 BLOCKED 呢就是加锁 synchronized ,这是整体的状态转换.
下面我们通过代码看一下状态的变化:
public static void main(String[] args) {
Thread thread = new Thread( () -> {
for (int i = 0; i < 1000_000; i++) {
// 在这个循环里什么也不干
}
});
// 此时 thread 得到的就是 NEW
System.out.println(thread.getState());
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
// thread 结束之后, 得到的状态就是 TERMINATED
System.out.println(thread.getState());
}
而在 start 和 join() 之间获取状态的话, 就是 RUNNABLE.
而我们要是在运行中的时候用上 sleep 和 join(time) 带时间的版本, 得到的状态就是 TIME_WAITING.
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread( () -> {
// for (int i = 0; i < 100_000_000; i++) {
// // 在这个循环里什么也不干
// }
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// 此时 thread 得到的就是 NEW
System.out.println(thread.getState());
thread.start();
Thread.sleep(50);
//thread.join(10000);
// thread 正在运行中, 此时得到的状态就是 RUNNABLE
System.out.println(thread.getState());
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
// thread 结束之后, 得到的状态就是 TERMINATED
System.out.println(thread.getState());
}
运行的时候, 遇到 sleep , 得到的状态就是 TIMED_WAITING, 没有的话就是 RUNNABLE 状态.
下面来看一下 BLOCKED 和 RUNNABLE 的转换:
处于 BLOCKED 状态的线程是因为在等待锁的释放。假如有两个线程 t1 和 t2,t1 线程提前获得了锁并且暂未释放锁,此时 t2 就处于 BLOCKED 状态。
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
test();
}
}, "t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
test();
}
}, "t2");
t1.start();
t2.start();
System.out.println(t1.getName() + ":" + t1.getState());
System.out.println(t2.getName() + ":" + t2.getState());
}
// 争夺锁
private static synchronized void test() {
try {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
从打印结果我们就可以看出来, t1 线程因为先于 t2 线程获得锁并且还在未释放的状态下, t1 线程处于 RUNNABLE 状态下, t2 线程处于 BLOCKED 状态下.
而当我们让 main 线程休眠1000毫秒的话, 此时线程状态转换就是:
- t1 的状态转换过程就是从开始启动线程的 RUNNABLE , 到 sleep 休眠的 TIMED_WAITING , 然后 sleep() 的时间一到, 就是 RUNNABLE, 然后和 t2 线程进行锁竞争,而由于没抢到锁就是到 BLOCKED(未加锁), 再到后面的 TERMINATED
- t2 的状态转换过程是, 从开始启动线程的 RUNNABLE , 到 BLOCKED(未抢到锁) ,然后也是 TERMINATED.