首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >项目织机:为什么虚拟线程不是默认的?

项目织机:为什么虚拟线程不是默认的?
EN

Stack Overflow用户
提问于 2022-04-20 20:32:49
回答 4查看 504关注 0票数 2

根据该项目的loom文档,虚拟线程的行为就像普通线程一样,具有几乎零的成本和将阻塞调用转换为非阻塞调用的能力。

如果这是真的,那他们为什么要分开呢?为什么不让它们成为默认的呢?有什么理由不使用它们吗?

EN

回答 4

Stack Overflow用户

发布于 2022-04-23 14:25:36

这里确实有两个问题: 1.为什么虚拟线程不是默认的?2.是否有理由不使用它们。

对于默认情况,Java实际上没有“默认”线程的概念。一旦虚拟线程到达,当您创建一个线程时,您必须指定您想要一个平台线程还是一个虚拟线程。接下来的问题是,为什么我们决定不自动用虚拟线程替换当前的线程(即让new Thread()创建一个虚拟线程)。答案很简单:它根本没有帮助,而且很可能是相当有害的。这不会有帮助,因为虚拟线程的优势来自于创建大量线程的能力。如果您的应用程序今天创建了N个线程,那么将这些N个线程转换为虚拟线程不会有什么好处。虚拟线程的扩展优势只有在应用程序创建1000 N线程时才会发挥作用,这意味着无论如何都需要对其进行更改(例如,将Executors.newFixedThreadPool替换为Executors.newVirtualThreadPerTaskExector)。这可能是有害的,因为虽然虚拟线程的语义与平台线程几乎相同,但它们并不完全向后兼容(详见9月425 )。

至于何时不使用虚拟线程的问题,有一些明显的例子。例如,当您的线程大量地与本机代码交互时,本机代码对虚拟线程一无所知,或者当您依赖于对虚拟线程已经更改的一些细节时,比如子类Thread的能力。其他情况则不太清楚。例如,与CPU内核相比,CPU绑定操作不会受益于更多的线程,因此它们不会从大量的虚拟线程中受益,但这并不意味着它们会受到损害。我们还没有准备好说默认情况下用户应该选择虚拟线程,但是我们很有可能做到这一点,因为我们了解了人们如何使用它们的更多信息。

票数 3
EN

Stack Overflow用户

发布于 2022-04-20 23:47:07

请注意,织机项目正在进行积极的试验开发。事情可能会改变。

无缺省值

你问:

为什么不让它们成为默认的呢?

在现代Java中,我们通常不直接寻址线程。相反,我们使用的是几年前在Java 5中添加的Executors框架。

特别是,在大多数情况下,Java程序员使用Executors实用程序类来生成ExecutorService。该执行器服务由各种线程工厂或线程池支持。

例如,如果您想一个接一个地序列化一个任务,我们将使用一个单线程支持的executor服务

代码语言:javascript
代码运行次数:0
运行
复制
ExecutorService executorService = Executors.newSingleThreadExecutor() ;

如果浏览Executors类Javadoc,您将看到各种各样的选项。其中没有一个是“默认”的。程序员选择一个以适应她特殊情况的需要。

有了工程织机,我们至少还有一个这样的选择可供选择。在Java的预览构建中,调用新的Executors.newVirtualThreadPerTaskExecutor()以获得由虚拟线程支持的执行器服务。去疯狂吧,把一百万项任务扔给它。

代码语言:javascript
代码运行次数:0
运行
复制
ExecutorService executorService = Executors.newVirtualThreadPerTaskExecutor() ;

你问:

他们为什么要把事情分开?

Java团队的首要任务之一是向后兼容性:现有的应用程序应该能够毫无意外地运行。

虚拟线程的行为和性能配置文件与平台线程非常不同。因此,我不希望看到Java团队将虚拟线程改造到Java的现有特性上。他们可能会选择这样做,但前提是必须绝对肯定,现有应用程序的行为不会出现任何有害影响。

何时选择或避免虚拟线程

你问:

有什么理由不使用它们吗?

是的,当然。原因有二:

  • CPU绑定任务
  • 用于间接节流其他资源的任务

CPU绑定任务

虚拟线程的全部目的是保持“真实”线程、平台主机-OS线程的忙碌。当一个虚拟线程阻塞,例如等待存储I/O或等待网络I/O时,虚拟线程从主机线程“卸载”,而另一个虚拟线程被“挂载”在主机线程上以完成某些执行。

因此,如果任务的代码没有阻塞,就不要使用虚拟线程。但是这种代码是很少见的。大多数应用程序中的大多数任务通常都在等待用户、存储、网络、附加设备等。一个罕见的任务可能不会被阻止的例子是CPU约束,比如视频编码/解码、科学数据分析或某种密集的数字处理。这些任务应该直接分配给平台线程,而不是虚拟线程。

节流

避免使用虚拟线程的另一个原因是现有代码依赖于平台线程的限制或瓶颈来限制应用程序对其他资源的使用。例如,如果一个数据库服务器仅限于10个同时连接,那么已经编写了一些应用程序来使用仅由8个或9个线程支持的executor服务。这种现有的代码不应该盲目地切换到虚拟线程。

当然,这样的代码不是最优的。如果使用了显式限制/节流机制,这样的代码库将更好、更清晰、更明显。

如果程序员想要在避免耗尽/重载其他有限资源的同时拥有成千上万甚至数百万的同步虚拟线程,则需要使用显式节流机制。

Java长期以来一直提供这样的节流机制。考虑到依赖于有限数量平台线程的限制/瓶颈的简单性/容易性,它们并不总是被使用。

我不是这方面的专家。所以要依靠那些专家。要获得详细信息和见解,请务必阅读这些文章,并观看罗恩·普雷斯勒、艾伦·贝特曼或项目织机团队的其他成员的演示和采访。

票数 2
EN

Stack Overflow用户

发布于 2022-09-29 17:38:58

我们先从

为什么不让它们成为默认的呢?

虚拟线程封装在平台线程上,因此您可能会认为它们是JVM提供的错觉,整个想法是将线程的生命周期设置为 CPU界 操作。

  • 平台线程与虚拟线程。平台线程在基于IO的任务和操作中将OS线程劫持为人质,仅限于线程池和OS线程中适用的线程数,默认情况下它们不是守护进程线程。
  • 虚拟线程是用JVM实现的,在CPU绑定操作中,与平台线程相关联并将它们重新组合到线程池中,在IO绑定操作完成后,将从线程池调用一个新线程,因此在本例中不存在任何问题。

第四层架构有更好的理解.

CPU

  • 多核CPU多核,具有cpu执行操作。

操作系统

  • OS线程OS调度程序将cpu时间分配给正在使用的OS线程。

JVM

  • 平台线程被完全包装在OS线程上,具有两个任务操作。
  • 在每个CPU绑定操作中,虚拟线程与平台线程相关联,每个虚拟线程可以在不同的时间与多个平台线程相关联。

带有可执行服务的虚拟线程

  • 使用executer服务更有效,因为它与线程池相关联--仅限于适用的线程池,但是在虚拟线程、Executer服务和虚拟包含的比较中,我们不使用ned来处理或管理关联的线程池。 尝试( service.submit(ExecutorServiceVirtualThread::taskOne);服务= Executors.newVirtualThreadPerTaskExecutor()) {ExecutorService service.submit(ExecutorServiceVirtualThread::taskTwo);}
  • Executer服务在JDK 19中实现了自动关闭接口,因此,当它与'try with resource‘一起使用时,一旦它到达'try’块的末尾,调用'close‘api,或者主线程将等待所有提交的任务与其专用的虚拟线程一起完成其生命周期,并关闭相关的线程池。 service.submit(ExecutorServiceThreadFactory::taskOne);工厂=Thread.ofVirtual().name(“用户线程-”,0).factory();try(ExecutorService service =Executors.newThreadPerTaskExecutor(工厂)){ ThreadFactory service.submit(ExecutorServiceThreadFactory::taskTwo);}
  • 也可以使用虚拟线程工厂创建Executer服务,只需将线程工厂与其构造函数参数放在一起即可。
  • 可以受益于执行服务的特点,如未来和可完成的未来。

虚拟线程优势

  • 显示与平台线程完全相同的行为。
  • 一次性的,可以被缩放到数百万。
  • 比平台线程轻量级得多。
  • 创建时间快,就像创建字符串对象一样快。
  • JVM对IO操作进行分隔,对于虚拟线程没有IO。
  • 但是可以像以前那样有顺序的代码,但是要有效得多。
  • JVM给人一种虚拟线程的错觉,整个故事下面是在平台线程上。
  • 随着虚拟线程CPU内核的使用变得更加并发,虚拟线程和多核CPU与ComputableFutures的结合对于并行化代码来说是非常强大的。

虚拟线程使用注意事项

  • 不要使用监视器,即同步块,但是这将在JDK的新版本中修复,另一种方法是使用“ReentrantLock”和try-final语句。
  • 在堆栈上阻塞本地帧,JNI‘。它非常罕见。
  • 每个堆栈的控制内存(减少线程区域设置,不进行深度递归)
  • 尚未更新的监视工具,如调试器、JConsole、VisualVM等

查找有关杰普-425的更多信息

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71945866

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档