1、Java定义了 6种线程状态
NEW 新生状态 new Thread() 线程即进入新生状态
RUNNABLE 可运行状态 t.start() 调用该方法后进入可运行状态(可运行说明可能正在执行也可能在等待或阻塞)
BLOCKED 阻塞状态:线程试图获得synchronized同步锁的这段时间内,处于阻塞状态
WAITING 等待状态:调用对象的 wait或者sleep 方法,将使当前线程进入等待状态
TIMED_WAITING 计时等他:调用wait(time)和sleep(time)都将进入计时等待
TERMINATED 被终止:线程正常执行完或者由于异常退出,都进入该状态
可能比较难区分的就是阻塞和等待这两种状态,按照Java对这两种状态的定义
其实也不难理解:blocking 阻塞,是线程试图进入被 synchronized 同步块时,当前线程要获得锁才能进入同步块
但这一刻可能锁被其他线程持有了,那当前线程其实就进入了 阻塞 状态
特别注意:线程调用 start 方法,就进入了 runnable可运行状态,进入同步块和进入 run 方法是完全不同的两个概念
只要 run 方法没有被 synchronized 修饰,那么所有线程在start 之后都能顺利进入 run 方法体
只是要进入 run 方法里面的同步块时,如果获取锁失败,才会进入阻塞!
2、演示线程的全状态
package com.test.concurrent.state;
import java.lang.Thread.State;
/**
* 演示线程的各种状态,并解释每个阶段的状态是如何转换的!
* 特别解释了 阻塞 和 等待 这两种状态的区别
* 也延伸出来 sleep 和 wait 最核心的区别
* sleep 不会释放当前持有的锁,但wait会释放
*
* @author yli
*/
public class ThreadStateTest {
// 定义一个对象,用来控制同步锁
public static Integer num = 0;
public static void main(String[] args) throws InterruptedException {
// Java定义了 6种线程状态
// NEW 新生状态 new Thread() 线程即进入新生状态
// RUNNABLE 可运行状态 t.start() 调用该方法后进入可运行状态(可运行说明很可能处于阻塞或者等待状态,不一定在运行)
// BLOCKED 阻塞状态:当线程获得synchronized同步锁的这段时间内,处于阻塞状态
// WAITING 等待状态:调用对象的 wait或者sleep 方法,将使当前线程进入等待状态
// TIMED_WAITING 计时等他:调用wait(time)和sleep(time)都将进入计时等待
// TERMINATED 被终止:线程正常执行完或者由于异常退出,都进入该状态
State[] states = Thread.State.values();
for (State s : states) {
System.out.println(s.toString());
}
System.out.println("*************************\n\n");
// NEW 新生状态
Thread t1 = new Thread(new ThreadState(), "t1");
Thread t2 = new Thread(new ThreadState(), "t2");
System.out.println("线程对象被创建,t1 线程状态:" + t1.getState());
System.out.println("线程对象被创建,t2 线程状态:" + t2.getState());
System.out.println("\n\n");
// 启动 t1 线程,main主线程休眠100毫秒,让t1运行起来
t1.start();
Thread.sleep(100);
// 100ms这段时间内 t1 会进入运行状态,并且进入同步块之后,线程会休眠2s
// 打印此时线程的状态:应该是 TIMED_WAITING 计时等待状态
System.out.println("t1的线程状态:" + t1.getState());
System.out.println("\n\n");
// 接下来启动t2线程,因为同一时刻只能有一个线程进入同步块(即只有一个线程可以获得锁)
// 由于 t1 获得锁之后,会休眠2s:休眠不会释放锁!!!这导致 t2 会被阻塞!!!
// 所以 t2 一开始能运行,进入run方法体,但尝试进入同步块,会阻塞
t2.start();
Thread.sleep(100); // 同样的主线程休眠100毫秒,让t2运行起来
System.out.println("t2的线程状态:" + t2.getState());
System.out.println("\n\n");
// 2s后,t1 休眠已结束,但马上调用了wait方法进入等待,再来看看 t1 此时的状态
Thread.sleep(2000);
System.out.println("t1的线程状态:" + t1.getState());
// t2 其实就比t1晚启动100毫秒,但t2启动后又让主线程休眠了100毫秒
// 所以再等2秒,t1和t2的sleep肯定都已经结束,都进入了wait计时等待
// 这里演示:使用 notifyAll 通知t1 和 t2 可以不再等待了
synchronized (ThreadStateTest.num) {
ThreadStateTest.num.notifyAll();
}
// 等t1 和 t2 全部运行完,来看看他们的状态
t1.join();
System.out.println("t1的线程状态:" + t1.getState());
t2.join();
System.out.println("t2的线程状态:" + t2.getState());
}
}
class ThreadState implements Runnable {
@Override
public void run() {
String tname = "线程:" + Thread.currentThread().getName();
System.out.println(tname + " 进入run方法块,线程状态:" + Thread.currentThread().getState());
synchronized (ThreadStateTest.num) {
System.out.println(tname + " 获得锁,进入同步块,线程状态:" + Thread.currentThread().getState());
try {
System.out.println(tname + " 进入sleep");
Thread.sleep(2000);
System.out.println(tname + " 进入wait");
ThreadStateTest.num.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
打印结果如下
NEW
RUNNABLE
BLOCKED
WAITING
TIMED_WAITING
TERMINATED
*************************
线程对象被创建,t1 线程状态:NEW
线程对象被创建,t2 线程状态:NEW
线程:t1 进入run方法块,线程状态:RUNNABLE
线程:t1 获得锁,进入同步块,线程状态:RUNNABLE
线程:t1 进入sleep
t1的线程状态:TIMED_WAITING
线程:t2 进入run方法块,线程状态:RUNNABLE
t2的线程状态:BLOCKED
线程:t1 进入wait
线程:t2 获得锁,进入同步块,线程状态:RUNNABLE
线程:t2 进入sleep
t1的线程状态:WAITING
线程:t2 进入wait
t1的线程状态:TERMINATED
t2的线程状态:TERMINATED