虚拟线程的特点
虚拟线程的接口和普通线程是一样的,但执行方式不同。虚拟线程不是由操作系统调度,而是由普通线程调度。任何时刻,只能执行一个虚拟线程,但一旦该虚拟线程执行一个IO操作进入等待时,它会被立刻“挂起”,然后执行下一个虚拟线程。这种机制使得虚拟线程非常适合处理IO密集型任务。
虚拟线程的优缺点
优点:
- 轻量级:可以在单个线程中创建成百上千个虚拟线程而不会导致过多的线程创建和上下文切换。
- 简化异步编程:虚拟线程可以简化异步编程,使代码更易于理解和维护。
- 减少资源开销:虚拟线程的上下文切换比平台线程更轻量,因此能够更好地支持高并发场景。
缺点:
- 不适用于计算密集型任务:虚拟线程适用于IO密集型任务,但不适用于计算密集型任务。
- 与某些第三方库不兼容:某些依赖平台线程特性的第三方库可能不完全兼容虚拟线程。
使用限制
虚拟线程在执行IO操作或Blocking操作时,会自动切换到其他虚拟线程执行,从而避免当前线程等待,能最大化线程的执行效率。但是,普通线程的IO操作仍然会等待。此外,在synchronized块内部也无法调度。
由于虚拟线程属于非常轻量级的资源,因此,用时创建,用完就扔,不要池化虚拟线程。
代码
public class VirtualThreadDemo {
public void demo(){
// 1. 直接创建并运行虚拟线程
Thread.startVirtualThread(() -> {
// something to do
});
// 2. 创建虚拟线程但不自动运行
Thread thread = Thread.ofVirtual().unstarted(() -> {
// something to do
});
thread.start();
// 3. 通过ThreadFactory创建虚拟线程
ThreadFactory factory = Thread.ofVirtual().factory();
Thread ft = factory.newThread(() -> {
// something to do
});
ft.start();
// 4. 使用Executors创建虚拟线程
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
}
/**
* 虚拟线程
*/
public void demoVirtualThread1(){
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
for (int i = 0; i < 100; i++) {
executor.submit(() -> {
// something to do
});
}
} catch (Exception e) {
log.error("demo exception", e);
}
}
/**
* 虚拟线程,等待所有结束
*/
public void demoVirtualThread2(){
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
List<CompletableFuture<Void>> futures = new ArrayList<>();
for (int i = 0; i < 100; i++) {
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
// something to do
}, executor);
futures.add(future);
}
// 等待所有任务完成
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
} catch (CompletionException e) {
log.error("demo CompletionException", e);
} catch (Exception e) {
log.error("demo exception", e);
}
}
}