1
0
mirror of https://github.com/Snailclimb/JavaGuide synced 2025-06-16 18:10:13 +08:00

[docs update] 新增 Java 21 虚拟线程部分内容

This commit is contained in:
JunQiu 2023-10-14 16:41:05 +08:00
parent 1962dbd0ea
commit b8c5c74047
2 changed files with 202 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -358,4 +358,206 @@ new 一个 `Thread`,线程进入了新建状态。调用 `start()`方法,会
**总结:调用 `start()` 方法方可启动线程并使线程进入就绪状态,直接执行 `run()` 方法的话不会以多线程的方式执行。**
## Java 21 虚拟线程
- 虚拟线程是一种轻量级的并发编程机制,它在代码中提供了一种顺序执行的感觉,同时允许在需要时挂起和恢复执行。虚拟线程可以看作是一种用户级线程,与操作系统的线程或进程不同,它是由编程语言或库提供的,而不是由操作系统管理的。
- 看下面的图大家也许更容易理解:
![虚拟线程、系统线程、平台线程对比](images/java-concurrent-questions-01/virtual-thread.png)
### 优点
- 非常轻量级:可以在单个线程中创建成百上千个虚拟线程而不会导致过多的线程创建和上下文切换。
- 简化异步编程: 虚拟线程可以简化异步编程使代码更易于理解和维护。它可以将异步代码编写得更像同步代码避免了回调地狱Callback Hell
- 减少资源开销: 相比于操作系统线程,虚拟线程的资源开销更小。本质上是提高了线程的执行效率,从而减少线程资源的创建和上下文切换。
### 缺点
- 不适用于计算密集型任务: 虚拟线程适用于I/O密集型任务但不适用于计算密集型任务因为密集型计算始终需要CPU资源作为支持。
- 依赖于语言或库的支持: 协程需要编程语言或库提供支持。不是所有编程语言都原生支持协程。比如 Java 实现的虚拟线程。
### 使用 Java 虚拟线程
- Java 21已经正式支持虚拟线程大家可以在官网下载使用在使用上官方为了降低使用门槛尽量复用原有的 Thread 类,让大家可以更加平滑的使用。
- 官方提供了以下几种方式:
#### 使用Thread.startVirtualThread()创建
```java
public class VirtualThreadTest {
public static void main(String[] args) {
CustomThread customThread = new CustomThread();
Thread.startVirtualThread(customThread);
}
}
static class CustomThread implements Runnable {
@Override
public void run() {
System.out.println("CustomThread run");
}
}
```
#### 使用Thread.ofVirtual()创建
```java
public class VirtualThreadTest {
public static void main(String[] args) {
CustomThread customThread = new CustomThread();
// 创建不启动
Thread unStarted = Thread.ofVirtual().unstarted(customThread);
unStarted.start();
// 创建直接启动
Thread.ofVirtual().start(customThread);
}
}
static class CustomThread implements Runnable {
@Override
public void run() {
System.out.println("CustomThread run");
}
}
```
#### 使用ThreadFactory创建
```java
public class VirtualThreadTest {
public static void main(String[] args) {
CustomThread customThread = new CustomThread();
ThreadFactory factory = Thread.ofVirtual().factory();
Thread thread = factory.newThread(customThread);
thread.start();
}
}
static class CustomThread implements Runnable {
@Override
public void run() {
System.out.println("CustomThread run");
}
}
```
#### 使用Executors.newVirtualThreadPerTaskExecutor()创建
```java
public class VirtualThreadTest {
public static void main(String[] args) {
CustomThread customThread = new CustomThread();
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
executor.submit(customThread);
}
}
static class CustomThread implements Runnable {
@Override
public void run() {
System.out.println("CustomThread run");
}
}
```
### 性能对比
- 通过多线程和虚拟线程的方式处理相同的任务,对比创建的系统线程数和处理耗时:
- 注:统计创建的系统线程中部分为后台线程(比如 GC 线程),两种场景下都一样,所以并不影响对比。
```java
public class VirtualThreadTest {
static List<Integer> list = new ArrayList<>();
public static void main(String[] args) {
// 开启线程 统计平台线程数
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
scheduledExecutorService.scheduleAtFixedRate(() -> {
ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
ThreadInfo[] threadInfo = threadBean.dumpAllThreads(false, false);
updateMaxThreadNum(threadInfo.length);
}, 10, 10, TimeUnit.MILLISECONDS);
long start = System.currentTimeMillis();
// 虚拟线程
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
// 使用平台线程
// ExecutorService executor = Executors.newFixedThreadPool(200);
for (int i = 0; i < 10000; i++) {
executor.submit(() -> {
try {
// 线程睡眠 0.5 s模拟业务处理
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException ignored) {
}
});
}
executor.close();
System.out.println("max" + list.get(0) + " platform thread/os thread");
System.out.printf("totalMillis%dms\n", System.currentTimeMillis() - start);
}
// 更新创建的平台最大线程数
private static void updateMaxThreadNum(int num) {
if (list.isEmpty()) {
list.add(num);
} else {
Integer integer = list.get(0);
if (num > integer) {
list.add(0, num);
}
}
}
}
```
#### 请求数10000 单请求耗时 1s
```plain
// Virtual Thread
max22 platform thread/os thread
totalMillis1806ms
// Platform Thread 线程数200
max209 platform thread/os thread
totalMillis50578ms
// Platform Thread 线程数500
max509 platform thread/os thread
totalMillis20254ms
// Platform Thread 线程数1000
max1009 platform thread/os thread
totalMillis10214ms
// Platform Thread 线程数2000
max2009 platform thread/os thread
totalMillis5358ms
```
#### 请求数10000 单请求耗时 0.5s
```plain
// Virtual Thread
max22 platform thread/os thread
totalMillis1316ms
// Platform Thread 线程数200
max209 platform thread/os thread
totalMillis25619ms
// Platform Thread 线程数500
max509 platform thread/os thread
totalMillis10277ms
// Platform Thread 线程数1000
max1009 platform thread/os thread
totalMillis5197ms
// Platform Thread 线程数2000
max2009 platform thread/os thread
totalMillis2865ms
```
- 可以看到在密集 IO 的场景下,需要创建大量的平台线程异步处理才能达到虚拟线程的处理速度。
- 因此,在密集 IO 的场景,虚拟线程可以大幅提高线程的执行效率,减少线程资源的创建以及上下文切换。
- 吐槽:虽然虚拟线程我很想用,但是我 Java8 有机会升级到 Java21 吗?呜呜
```
注:有段时间 JDK 一直致力于 Reactor 响应式编程来提高Java性能但响应式编程难以理解、调试、使用最终又回到了同步编程最终虚拟线程诞生。
```
<!-- @include: @article-footer.snippet.md -->