1. 线程的状态及变化
线程的状态反应了线程的一个生命周期,我们创建启动一个线程以后,线程处于就绪状态,当操作系统调度,使得线程获取到CPU时间片以后,线程处于执行状态,线程执行结束以后,线程处于终结状态。如果线程在执行过程中,竞争锁失败,则会进入阻塞状态;如果线程执行的代码中存在Object.wait()、Thread.join()方法时,线程会进入无限等待,即等待状态,需要其他线程帮助唤醒;如果线程执行的代码中只是因为存在Thread.sleep(n)、Object.wait(timedout)等带了超时时间方法而被阻塞时,线程处于超时阻塞状态。

就绪:在Java中,我们创建一个线程,执行start()方法后,线程处于就绪状态,因为此时还没有获得CPU时间片,没有真正开始执行。
运行:当线程经过操作系统调度获得CPU时间片以后,线程开始执行,线程进入运行状态。
阻塞:线程在执行代码过程中,存在竞争Synchronized、Lock锁的时候,如果经常失败,则线程进入阻塞状态,当线程获取到锁以后,线程重新进入就绪状态。
等待:线程在代码执行过程中,遇到Thread.join()、Object.wait()等方法后,线程进入等待状态。因Thread.join()方法阻塞的线程等待调用join()方法的线程执行结束以后,会进入就绪状态。因Object.wait()方法方法阻塞的线程,需要其他线程执行Object.notify()或者Object.notifyAll()方法来唤醒,不过唤醒后应该进入的是阻塞状态,因为可能还没拿到对应的锁。
超时等待:线程在代码执行过程中,遇到Thread.sleep(n)、Object.wait(timedout)方法后,会进入超时等待状态,到达设定的时间后,线程会进入就绪状态,等待执行
2. 线程是如何进入各种状态的?
现在我们已经知道如何构建和启动一个线程,现在通过几段代码演示一下线程如何进入各种状态。
RUNNABLE状态
java
private static Object object = new Object();
static void runnableState() throws InterruptedException {
Thread t = Thread.ofVirtual().start(() -> {
System.out.println("thread status is " + Thread.currentThread().getState());
});
t.join();
}
BLOCKED
java
static void blockState() throws InterruptedException {
Thread t1 = Thread.ofVirtual().name("t1_Thread").start(() -> {
synchronized (object) {
System.out.println(Thread.currentThread().getName() + " status is " + Thread.currentThread().getState());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
Thread.sleep(100);
Thread t2 = Thread.ofVirtual().name("t2_Thread").start(() -> {
synchronized (object) {
System.out.println(Thread.currentThread().getName() + " start run , status is " + Thread.currentThread().getState());
}
});
// 这里需要加这一句,不然t2启动后可能还没开始竞争锁,导致下面输出的t2的状态是 RUNNABLE
Thread.sleep(100);
System.out.println(t2.getName() + " status is " +t2.getState());
t1.join();
t2.join();
}
这里t1线程获取锁之后,被Thread.sleep(1000)阻塞住,导致t2线程暂时拿不到锁,t2线程的状态为BLOCKED
WAITTING
java
static void waittingThread() throws InterruptedException {
Thread t = Thread.ofVirtual().name("t_thread").start(()->{
// 这里必须用synchronized修饰,wait要和synchronized配合使用
synchronized (object){
try {
object.wait();
System.out.println(Thread.currentThread().getName() + " pass wait ");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
Thread.sleep(100);
System.out.println(t.getName() + " status is " +t.getState());
Thread.ofVirtual().start(()->{
synchronized (object){
object.notify();
}
});
Thread.sleep(100);
System.out.println(t.getName() + " status is " +t.getState());
t.join();
}
这里线程t执行到object.wait()时,线程会停止执行,并处于WAITTING状态,直到下面有新的线程执行了object.notify(),线程t才会恢复运行。
TIMED_WAITING
java
static void timedoutWaitThread() throws InterruptedException {
Thread t = Thread.ofVirtual().name("t_thread").start(()->{
synchronized (object){
try {
object.wait(100);
System.out.println(Thread.currentThread().getName() + " pass time_wait ");
System.out.println(Thread.currentThread().getName() + " status is " + Thread.currentThread().getState());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
Thread.sleep(50);
System.out.println(t.getName() + " status is " +t.getState());
t.join();
}
这里线程t执行到object.wait(100)时,线程会停止执行,并处于TIMED_WAITING 状态,因为object.wait(100)设置了100毫秒的等待时间,100毫秒后,线程自动从TIMED_WAITING状态恢复,继续执行。