tl;dr
Select 平台线程而不是虚拟线程的原因不是因为任务的生存期有多长,而是(A)如果任务阻塞很少,或者(B)如果任务有synchronized
个长时间运行的代码.否则,最好使用虚拟线程.
Details
我怀疑你想得太多了.情况并不真的那么复杂.
在JAVA 21和更高版本的…中
定义您想要以Runnable
或Callable
运行的任何任务.
如果您不关心任务是否并发运行,则通过execute
方法将其传递给Executor
实例.
如果您确实希望该任务并发运行,请通过submit
或invoke…
方法传递给ExecutorService
.
如果任务涉及阻塞,则使用Executor服务,该服务 for each 任务分配一个新的virtual thread."新的"意味着一个新的、干净的、最小的堆栈,并且没有预先存在的ThreadLocal
个对象."阻塞"意味着等待一些事情,这样线程就不能做任何进一步的工作;基本上是任何I/O,如日志(log)记录、文件读/写、对数据库的调用和网络流量.虚拟线程非常"便宜",这意味着创建速度快、内存效率高、CPU效率高.
换句话说,虚拟线程类似于facial tissues:无论何时需要,都可以获取一个新的线程,使用它,然后进行处理.
如果您的任务涉及标记为synchronized
的长时间运行的代码,请将synchronized
替换为ReentrantLock
,或者使用平台线程运行它,如下所述.
如果您的任务(A)不涉及阻塞(受CPU限制,例如视频编码),或者(B)调用本机代码(JNI或JEP 454),则不要使用虚拟线程.将这样的任务提交给由平台线程支持的执行器服务(S).如果担心计算机负担过重,请使用由有限数量的线程池支持的Executor服务.
平台线程是"昂贵的".因此,如果您的任务满足上述条件,则最好使用虚拟线程.虚拟线程中的任务可能会短暂运行,也可能会运行很长时间,甚至整个应用程序的持续时间.
在使用池化线程时,请注意清除ThreadLocal
个对象,以避免被该线程中的后续任务意外使用.
始终在结束应用程序之前关闭Executor服务.否则,支持线程可能会无限期运行,就像僵尸🧟♂️一样.要么使用Try-With-Resources语法自动关闭,要么使用ExecutorService
个Javadoc中给出的样板代码.
仅供参考,虚拟线程实际上在JVM自动管理的池中的平台线程上运行您的任务.
要了解更多信息,请阅读上面链接的JEP.请看Ron Pressler、Alan Bateman和José Paumard的演讲.