【多线程:线程六种状态详解】
01.介绍
我们之前已经介绍过了线程的六种状态,但是介绍的比较浅显,这里我们更加深刻的理解一下线程的六种状态及其代码示例。
02.线程的六种状态
图片解释
NEW 线程刚被创建,但是还没有调用 start() 方法RUNNABLE 当调用了 start() 方法之后,注意,Java API 层面的 RUNNABLE 状态涵盖了 操作系统 层面的 【可运行状态】、【运行状态】和【阻塞状态】(由于 BIO 导致的线程阻塞,在 Java 里无法区分,仍然认为 是可运行)
BLOCKED , WAITING , TIMED_WAITING 都是 Java API 层面对【阻塞状态】的细分,后面会在状态转换一节 详述 TERMINATED 当线程代码运行结束
这里最应该注意的是RUNNABLE状态 其实是包括了 可运行 运行 阻塞 三个状态,其中阻塞状态是操作系统IO层面的 与 BLOCKED不一样
RUNNABLE 中 阻塞状态 代码
public class TestState2 {
public static void main(String[] args) throws InterruptedException {
new Thread(() -> {
FileReader.read(Constants.FilePath);
}, "t1").start();
Thread.sleep(50); // 7行
System.out.println("ok");
}
}
结果
我们在第7行打上断点 查看此时t1的状态
可以看出当我们主线程在睡眠50ms期间 t1线程正在读取文件 但还没有读完 此时t1现在属于IO阻塞 但是我们在debug界面可以看到 t1线程现在是RUNNING(就是RUNNABLE debug页面叫做RUNNING)
六种状态示例代码
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
@Slf4j(topic = "c.TestState")
public class TestState {
public static void main(String[] args) throws IOException {
Thread t1 = new Thread("t1") {
@Override
public void run() {
log.debug("running...");
}
}; // NEW
Thread t2 = new Thread("t2") {
@Override
public void run() {
while(true) { // RUNNABLE
}
}
};
t2.start();
Thread t3 = new Thread("t3") {
@Override
public void run() {
log.debug("running...");
}
};// TERMINATED
t3.start();
Thread t4 = new Thread("t4") {
@Override
public void run() {
synchronized (TestState.class) {
try {
Thread.sleep(1000000); // TIMED_WAITING
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
t4.start();
Thread t5 = new Thread("t5") {
@Override
public void run() {
try {
t2.join(); // WAITING
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
t5.start();
Thread t6 = new Thread("t6") {
@Override
public void run() {
synchronized (TestState.class) { // BLOCKED
try {
Thread.sleep(1000000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
t6.start();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("t1 state {}", t1.getState());
log.debug("t2 state {}", t2.getState());
log.debug("t3 state {}", t3.getState());
log.debug("t4 state {}", t4.getState());
log.debug("t5 state {}", t5.getState());
log.debug("t6 state {}", t6.getState());
System.in.read();
}
}
结果
16:36:39.975 c.TestState [t3] - running...
16:36:40.474 c.TestState [main] - t1 state NEW
16:36:40.475 c.TestState [main] - t2 state RUNNABLE
16:36:40.475 c.TestState [main] - t3 state TERMINATED
16:36:40.476 c.TestState [main] - t4 state TIMED_WAITING
16:36:40.476 c.TestState [main] - t5 state WAITING
16:36:40.476 c.TestState [main] - t6 state BLOCKED
解释
我们一个一个来分析
t1:我们创建了一个线程对象t1 但没有进行start所以状态为NEW
t2:t2线程的run方法里是一个永真循环 一直占用cpu 所以是RUNNABLE状态
t3:t3线程run方法里就只有一个输出语句 当运行完后 此线程终结 所以状态为 TERMINATED
t4:t4线程run方法里有一个sleep方法 线程睡眠期间属于TIMED_WAITING状态 期间不参与cpu调度 睡眠结束后变为就绪态(RUNNABLE中的可运行状态)
t5:t5线程run方法里有一个t2线程的join方法 t2线程同步到t5线程 同步期间 t5线程为 WAITING状态 期间不参与cpu调度 t2线程结束后 t5线程变为就绪态(RUNNABLE中的可运行状态)
t6:t6线程与t4线程都被加锁 其监听器都为 TestState.class,又因为此时t4线程先被锁定,t6线程此时没有抢到锁 所以此时t6线程为BLOCKED状态 此状态不参与cpu调度 获得锁后转变为就绪态 注意与 RUNNABLE里的阻塞不是一个东西 RUNNABLE阻塞指的是IO层面的阻塞,BLOCKED指的是java层面的阻塞