JDK19中如何获取承载虚拟线程的平台线程及相关复用问题
JDK19虚拟线程相关问题解答
获取虚拟线程对应的承载平台线程
可以通过虚拟线程的carrierThread()方法获取当前承载它的平台线程。需要注意的是,虚拟线程在调度过程中可能会切换到不同的平台线程,因此这个返回值是动态变化的,只有在虚拟线程处于运行状态时,返回的才是当前正在执行它的平台线程。
示例代码:
// 在虚拟线程内部获取当前承载的平台线程 VirtualThread currentVt = VirtualThread.current(); Thread carrierThread = currentVt.carrierThread(); System.out.println("当前承载平台线程ID: " + carrierThread.getId());
固定虚拟线程到某一平台线程并访问其ThreadLocal
固定虚拟线程到平台线程
JDK19的VirtualThread.Builder提供了carrierThread(Thread)方法,可以将虚拟线程绑定到指定的平台线程上,这样虚拟线程的所有执行逻辑都会在该平台线程上完成,不会被调度到其他平台线程。
示例代码:
// 创建一个平台线程 Thread fixedPlatformThread = new Thread(() -> { // 保持平台线程存活,以便虚拟线程可以运行 synchronized (fixedPlatformThread) { try { fixedPlatformThread.wait(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }); fixedPlatformThread.start(); // 创建绑定到该平台线程的虚拟线程 VirtualThread vt = VirtualThread.builder() .carrierThread(fixedPlatformThread) .task(() -> { // 虚拟线程的执行逻辑 System.out.println("虚拟线程运行在平台线程ID: " + VirtualThread.current().carrierThread().getId()); }) .build(); vt.start();
访问平台线程的ThreadLocal
平台线程的ThreadLocal是线程私有数据,虚拟线程无法直接访问其他线程的ThreadLocal值。如果需要让虚拟线程获取平台线程的ThreadLocal内容,有两种可行方式:
- 传递值:在创建虚拟线程时,将平台线程的
ThreadLocal值作为参数传递给虚拟线程的任务逻辑。 - 使用可继承ThreadLocal:如果平台线程的
ThreadLocal是InheritableThreadLocal,且虚拟线程创建时开启了线程本地继承(默认开启,可通过inheritThreadLocals(false)关闭),虚拟线程会继承平台线程的InheritableThreadLocal值。
示例代码(传递值方式):
ThreadLocal<String> platformThreadLocal = new ThreadLocal<>(); Thread fixedPlatformThread = new Thread(() -> { platformThreadLocal.set("平台线程的ThreadLocal值"); // 将值传递给虚拟线程 String threadLocalValue = platformThreadLocal.get(); VirtualThread vt = VirtualThread.builder() .carrierThread(fixedPlatformThread) .task(() -> { System.out.println("获取到平台线程的ThreadLocal值: " + threadLocalValue); }) .build(); vt.start(); synchronized (fixedPlatformThread) { try { fixedPlatformThread.wait(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }); fixedPlatformThread.start();
虚拟线程中的对象复用(类似Golang sync.Pool)
JDK没有提供和Golang sync.Pool完全一致的API,但可以基于ThreadLocal和队列实现类似的线程本地对象缓存,达到对象复用的目的。这种实现方式中,每个线程拥有自己的对象池,线程可以复用自己缓存的对象,避免频繁创建销毁带来的开销,同时当线程被回收时,对应的本地缓存也会被清理。
示例实现:
import java.util.ArrayDeque; import java.util.Deque; import java.util.function.Supplier; public class ThreadLocalObjectPool<T> { private final Supplier<T> objectSupplier; private final ThreadLocal<Deque<T>> threadLocalPool = ThreadLocal.withInitial(ArrayDeque::new); public ThreadLocalObjectPool(Supplier<T> objectSupplier) { this.objectSupplier = objectSupplier; } // 获取对象,优先从本地缓存取,缓存为空则创建新对象 public T acquire() { Deque<T> pool = threadLocalPool.get(); T obj = pool.poll(); return obj != null ? obj : objectSupplier.get(); } // 归还对象到本地缓存 public void release(T obj) { threadLocalPool.get().offer(obj); } }
使用示例:
// 创建一个StringBuilder对象池 ThreadLocalObjectPool<StringBuilder> pool = new ThreadLocalObjectPool(StringBuilder::new); // 在虚拟线程中复用对象 VirtualThread.startVirtualThread(() -> { StringBuilder sb = pool.acquire(); try { sb.append("虚拟线程复用对象"); System.out.println(sb.toString()); } finally { // 清空对象状态后归还 sb.setLength(0); pool.release(sb); } });
内容的提问来源于stack exchange,提问作者user9959339
相关产品推荐
相关产品推荐

