一、虚拟线程
虚拟程是Java语言中实现的一种轻量级线程,由Java虚拟机(JVM)管理而非操作系统,其核心优势在于高并发场景下的资源效率和性能提升。 旨在解决传统操作系统线程资源占用大、调度开销高的问题。
二、虚拟线程和传统线程相比,优势非常明显,主要体现在三个方面:
1. 资源占用极低,支持百万级并发
传统线程每个需要占用 1MB 左右的栈空间,一旦创建几千个,服务器内存就容易被耗尽;而虚拟线程初始栈空间仅 100-200KB,一次创建 100 万个都不成问题。打个比方,传统线程像 “大卡车”,一次拉不了几箱货;虚拟线程像 “小电动车”,一次能跑几百辆,运输效率直接拉满。
2. 无需手动调参,JVM 自动适配负载
以前用线程池,得反复纠结 “核心线程数设多少?最大线程数要不要增加?任务队列容量够不够?”,参数调不好就会出现线程溢出或资源浪费。虚拟线程完全不用操心这些,JVM 会根据任务负载自动调度,开发者只需提交任务,剩下的交给 JVM 就行,省心又高效。
3. IO 阻塞不占 CPU,资源利用率大幅提升
传统线程遇到 IO 操作(比如调用接口、查询数据库)时,会一直 “霸占” CPU 等待结果,导致 CPU 空转;而虚拟线程在 IO 阻塞时,会主动释放 CPU 资源,让其他任务继续执行,等 IO 操作有结果后再重新获取 CPU。这样一来,CPU 利用率能从原来的 50% 左右提升到 90% 以上,服务器性能充分释放。
三、虚拟线程VS传统线程
传统 Java 线程就像一辆辆大巴车(重量级,启动成本高)
而虚拟线程更像很多小电动车(数量多,快速启停,占用内存低)
四、四种创建虚拟线程(Java 21+)
方案一:使用Thread.startVirtualThread()方法,方法内部会自动开启线程
// 方式1:快速启动虚拟线程
Thread th= Thread.startVirtualThread(() -> {
System.out.println(Thread.currentThread());
System.out.println("startVirtualThread!");
});
//等待虚拟线程执行完毕
try {
th.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}

方案二:使用Thread.ofVirtual()方法,创建虚拟线程
//方式2:Builder模式
Thread th= Thread.ofVirtual().name("virtualThread-1").start(() -> {
System.out.println(Thread.currentThread());
System.out.println("ofVirtual!");
});
//等待虚拟线程执行完毕
try {
th.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}

方案三:通过Thread.ofVirtual).factory0方法获取一个线程工厂,再通过线程工厂创建虚拟线程
// 方式3:工厂模式
ThreadFactory factory = Thread.ofVirtual().factory();
// 创建虚拟线程
Thread th = factory.newThread(() -> {
System.out.println(Thread.currentThread());
System.out.println("ThreadFactory!");
});
// 启动虚拟线程
th.start();
//等待虚拟线程执行完毕
try {
th.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}

方案四:使用Executors.newVirtualThreadPerTaskExecutor()方法,创建虚拟线程(推荐)
// 方式4:使用ExecutorService(推荐!)
ExecutorService executor= Executors.newVirtualThreadPerTaskExecutor();
//每次提交一个任务,都会创建一个虚拟线程
Future<?> future1= executor.submit(() -> {
System.out.println(Thread.currentThread());
System.out.println("Runnable任务执行完成!");
});
// 提交Callable任务
Future<String> future2 = executor.submit(() -> {
Thread.sleep(2000);
return "Callable任务返回值";
});
// 获取Callable任务结果
try {
String result = future2.get();
System.out.println("任务结果: " + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
// 关闭线程池
executor.shutdown();

五、使用虚拟线程Java实现网络通信
(1) 服务器端
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class MyServer {
public static void main(String[] args) {
int port=8888;
try {
//创建服务器端Socket,绑定到指定端口上
ServerSocket server=new ServerSocket(port);
System.out.println("服务器启动,等待客户端连接...");
while (true){
//阻塞等待客户端连接
Socket socket=server.accept();
//启动一个线程,等待客户端连接
Thread.ofVirtual().start(() -> {
//通过socket获取输入流和输出流
try( PrintWriter out=new PrintWriter(socket.getOutputStream(),true);
BufferedReader in=new BufferedReader(new InputStreamReader(socket.getInputStream()));) {
String line;
//循环读取客户端发送的消息
while((line=in.readLine())!=null){
//获取当前线程信息,并将其转换为字符串
String thInfo=Thread.currentThread().toString();
//将客户端发送的消息打印到控制台,并加上线程信息
out.println(thInfo+":"+line);
}
}catch (Exception e){
e.printStackTrace();
}
});
}
}catch (Exception e){
e.printStackTrace();
}
}
}
(2) 客户端
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class MyClient {
public static void main(String[] args) {
try {
//创建客户端Socket,与服务端建立连接
Socket socket=new Socket("localhost",8888);
//创建输入输出流对象
BufferedReader stdin=new BufferedReader(new InputStreamReader(System.in));
PrintWriter out=new PrintWriter(socket.getOutputStream(),true);
BufferedReader in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
String cline;
//循环读取控制台输入,并将其发送给服务端
while((cline=stdin.readLine())!=null){
out.println(cline);
//读取服务端返回的消息,并打印到控制台
System.out.println(in.readLine());
if("bye".equals(cline)){
break;
}
}
}catch (Exception e){
e.printStackTrace();
}
}
}
(3) 启动服务端

(4) 启动客户端2个,输入bye就结束!

六、适用场景
- 虚拟线程适用于执行阻塞式任务,在阻塞期间,可以将CPU资源让渡给其他任务
- 虚拟线程不适合CPU密集计算或非阻塞任务,虚拟线程并不会运行的更快,而是增加了规模
- 虚拟线程是轻量级资源,用完即抛,不需要池化
- 通常我们不需要直接使用虚拟线程,像Tomcat、Jetty、Netty、Springboot等都已支持虚拟线程
2368

被折叠的 条评论
为什么被折叠?



