老生常谈
线程的状态这个话题老生常谈了,但是一定要纠正下,网上的诸多资料太乱,有的说的根本就是错的。Java线程的状态和操作系统的状态根本就是两回事,不可混淆。Java线程的状态位于上层,一个Java状态可能对应N个操作系统的线程状态。
状态枚举
中文翻译过来的状态太多叫法,还是得英文原本的叫法。
public enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
}
1、NEW:刚创建尚未启动线程。
2、RUNNABLE: 复合状态,包含有2个状态:Ready和Running。
3、BLOCKED:线程在等待锁时。
4、WAITING:调用wait、join等方法。
5、TIMED_WAITING: sleep(time)
6、TERMINATED:run方法执行结束。
JVisualVM中将状态分为运行、休眠、等待、驻留、监视。
它们几个和Thread的状态的对应关系是:
Thread类 | VisualVM |
---|---|
RUNNABLE | 运行 |
TIMED_WAITING (sleeping) | 休眠 |
TIMED_WAITING (on object monitor) WAITING (on object monitor) | 等待 |
TIMED_WAITING (parking) WAITING (parking) | 驻留 |
BLOCKED (on object monitor) | 监视 |
线程状态转换图
来自:https://www.uml-diagrams.org/java-thread-uml-state-machine-diagram-example.html
示例1
package com.sss.concurrency.thread.status;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ThreadStatusTest1 {
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
public void test1(){
Thread t1 = new Thread(() -> {
try {
System.out.println("3秒后再次运行,然后进入wait状态");
TimeUnit.SECONDS.sleep(3);
lock.lock();
condition.await();
int i = 0;
while(i++ < 100000000){
}
lock.unlock();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "t1");
new Thread(()->{
try {
TimeUnit.SECONDS.sleep(5);
lock.lock();
TimeUnit.SECONDS.sleep(5);
condition.signalAll();
lock.unlock();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"notify线程").start(); //notify线程
System.out.println(t1.getState());
t1.start();
while(true){
System.out.println(t1.getState());
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new ThreadStatusTest1().test1();
}
}
NEW
RUNNABLE
3秒后再次运行,然后进入wait状态
TIMED_WAITING
TIMED_WAITING
WAITING
WAITING
WAITING
WAITING
WAITING
WAITING
WAITING
TERMINATED
TERMINATED
TERMINATED
TERMINATED
Process finished with exit code -1
第一个示例演示了从NEW到RUNNABLE再到TIMED_WAITING,最后TERMINATED的转变
示例2
package com.sss.concurrency.thread.status;
import java.util.concurrent.TimeUnit;
public class ThreadStatusTest2 implements Runnable{
public static void main(String[] args) {
ThreadStatusTest2 threadStatusTest2 = new ThreadStatusTest2();
Thread t1 = new Thread(threadStatusTest2, "t1");
Thread t2 = new Thread(threadStatusTest2, "t2");
new Thread(()->{
while(true){
System.out.println("t1.state=" + t1.getState());
System.out.println("t2.state=" + t2.getState());
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
t1.start();
t2.start();
}
@Override
public void run() {
synchronized (this){
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
t1.state=RUNNABLE
t2.state=BLOCKED
t1.state=TIMED_WAITING
t2.state=BLOCKED
t1.state=TIMED_WAITING
t2.state=BLOCKED
t1.state=TERMINATED
t2.state=TIMED_WAITING
t1.state=TERMINATED
t2.state=TIMED_WAITING
t1.state=TERMINATED
t2.state=TIMED_WAITING
t1.state=TERMINATED
t2.state=TERMINATED
第二个示例演示了线程状态从RUNNABLE–>BLOCKED---->TERMINATED的转变。
示例3
package com.sss.concurrency.thread.status;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.channels.FileChannel;
import java.util.concurrent.TimeUnit;
public class ThreadStatusTest3 implements Runnable{
public static void main(String[] args) {
ThreadStatusTest3 threadStatusTest2 = new ThreadStatusTest3();
Thread t1 = new Thread(threadStatusTest2, "t1");
new Thread(()->{
while(true){
System.out.println("t1.state=" + t1.getState());
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
t1.start();
}
@Override
public void run() {
ServerSocket server = null;
try {
server = new ServerSocket(8000);
System.out.println("服务器准备就绪~");
System.out.println("服务器信息:" + server.getInetAddress() + " P:" + server.getLocalPort());
// 等待客户端连接
while(true) {
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
t1.state=RUNNABLE
服务器准备就绪~
服务器信息:0.0.0.0/0.0.0.0 P:8000
t1.state=RUNNABLE
t1.state=RUNNABLE
t1.state=RUNNABLE
t1.state=RUNNABLE
t1.state=RUNNABLE
第3个示例说明了网络IO的阻塞,线程状态不是BLOCKED,而是RUNNABLE。
就算是IO阻塞或者网路阻塞,对于JVM而言,程序是在运行啊。JVM把网卡啊、cpu也好,都认为有资源在为线程服务。