Java21虚拟线程的注意点
- ThreadLocal能继续用么?Java 开发组设计虚拟线程的时候,原本想去掉对 ThreadLocal 的支持。但由于使用它的库太多,并且很多为了传参才用,并不是缓存,所以就保持了支持。像隐式传参的这种场景,继续用也没事儿,就是性能有所损耗。(不会影响 GC,生命周期随着虚拟线程终止,但是线程本地变量数量变多,哈希表变大,需要频繁清理)。千万别在虚拟线程的 ThreadLocal 存放大对象。Java 开发组是想通过 ScopedLocal 替换掉 ThreadLocal(这个没有大哈希表的问题),但是在 21 还只是 preview。
- 虚拟线程主要通过 Continuation 实现,虚拟线程栈会在切换的时候复制到 Continuation 中,切换回来的时候,再复制回来,但是不是每次都全量复制。在切换回来的时候,线程栈帧懒复制,调用返回到哪个就复制回哪个。这对于像是 servlet 这种很多层调用的是很大的优化,因为栈深度可能有 上百层,但是实际业务只会用到头部几层的场景的提升尤其明显。这样大大减少了切换的性能消耗。
- 网络 io 方面,虚拟线程目前完全不会阻塞了。
- 文件 io 方面,目前实现方式是遇到就增加一个平台线程来规避阻塞。这个会在 io_uring 引入到 JVM 支持后进行优化,到时候文件 io 也原生不会阻塞。
- JFR,Thread Stack Dump,调试器, JVM TI 都可以兼容虚拟线程。但是要记住,调试虚拟线程可能也会让其他虚拟线程无法执行,因为载波线程是同一个。
- synchronized 以及涉及 ObjectMonitor 的,都还是会 pin 住载体平台线程,要在你的代码中避免使用。
- 虚拟线程无法 getAllThreads(),这个方法返回的是所有平台线程。
- 所有 JMX 以及 java.lang.management 相关的都是处理平台线程,不支持 VirtualThread。
- 虚拟线程支持类似于 jstack 的 dump,但是命令有所不同,请通过 jcmd 获取。并且格式是 json,没有死锁信息(虚拟线程 dump 不会进入全局安全点STW所以无法获取一致性信息例如死锁等)