openjdk8 项目结构_OpenJDK织机和结构化并发

openjdk8 项目结构

Project Loom是Hotspot Group赞助的项目之一,旨在向JAVA世界提供高吞吐量和轻量级的并发模型。 在撰写本文时,Loom项目仍在积极开发中,其API可能会更改。

为什么要织机?

每个新项目可能会出现的第一个问题是为什么?
为什么我们需要学习新的东西,它对我们有帮助? (如果确实如此)

因此,要专门针对Loom回答此问题,我们首先需要了解JAVA中现有线程系统如何工作的基础知识。

JVM内部产生的每个线程在OS内核空间中都有一个一对一的对应线程,并具有自己的堆栈,寄存器,程序计数器和状态。 每个线程的最大部分可能是堆栈,堆栈大小以兆字节为单位,通常在1MB到2MB之间。
因此,这些类型的线程在启动和运行时方面都很昂贵。 不可能在一台机器上产生1万个线程并期望它能正常工作。

有人可能会问为什么我们甚至需要那么多线程? 鉴于CPU只有几个超线程。 例如,CPU Internal Core i9总共有16个线程。
好吧,CPU并不是您的应用程序使用的唯一资源,任何没有I / O的软件都只会导致全球变暖!
一旦线程需要I / O,操作系统就会尝试为其分配所需的资源,并同时调度另一个需要CPU的线程。 因此,我们在应用程序中拥有的线程越多,我们就越可以并行利用这些资源。

一个非常典型的示例是Web服务器。 每台服务器能够在每个时间点处理数千个打开的连接,但是同时处理多个连接要么需要数千个线程,要么需要异步非阻塞代码( 可能会在接下来的几周内撰写另一篇文章,以解释更多有关异步代码 ),就像前面提到的,成千上万个OS线程既不是您也不是OS会满意的!

织机如何提供帮助?

作为Project Loom的一部分,引入了一种称为Fiber的新型线程。 光纤也称为虚拟线程绿色线程或用户线程,因为这些名称暗示完全由VM处理,并且OS甚至都不知道此类线程存在。 这意味着并非每个VM线程都需要在OS级别具有相应的线程! 虚拟线程可能被I / O阻塞或等待从另一个线程获取信号,但是,与此同时,其他虚拟线程也可以利用基础线程!

上图说明了虚拟线程和OS线程之间的关系。 虚拟线程可以简单地被I / O阻塞,在这种情况下,基础线程将被另一个虚拟线程使用。

这些虚拟线程的内存占用量将以千字节为单位,而不是兆字节。 如果需要,可以在生成它们之后扩展它们的堆栈,这样JVM不需要为它们分配大量内存。

因此,既然我们有一种非常轻巧的方式来实现并发,我们就可以重新考虑存在于Java经典线程中的最佳实践。

如今,在Java中实现并发最常用的结构是ExecutorService的不同实现。 它们具有非常方便的API,并且相对易于使用。 执行程序服务具有一个内部线程池,用于根据开发人员定义的特征来控制可以产生多少个线程。 该线程池主要用于限制应用程序创建的OS线程的数量,因为如上所述,它们是昂贵的资源,我们应该尽可能地重用它们。 但是现在可以生成轻量级虚拟线程了,我们也可以重新考虑使用ExecutorServices的方式。

结构化并发

结构化并发是一种编程范例,是一种编写易于读取和维护的并发程序的结构化方法。 如果代码对并发任务有明确的入口和出口点,则其主要思想与结构化编程非常相似,与启动可能比当前作用域更长的并发任务相比,对代码的推理要容易得多!

为了更清楚地了解结构化并发代码的外观,请考虑以下伪代码:

 void notifyUser(User user) { try (var scope = new ConcurrencyScope()) { scope.submit( () -> notifyByEmail(user)); scope.submit( () -> notifyBySMS(user)); } LOGGER.info( "User has been notified successfully" );  } 

notifyUser方法应该通过电子邮件和SMS通知用户,一旦成功完成此方法将记录一条消息。 使用结构化并发,可以保证在两种通知方法都完成后立即写入日志。 换句话说,如果尝试范围在其中所有已启动的并发作业都完成了,那么它将完成!

注意:为了使示例简单,我们假设notifyByEmail和notifyBySMS在上面的示例中,在内部确实处理所有可能的极端情况,并始终使其通过。

JAVA的结构化并发

在本节中,我将通过一个非常简单的示例展示如何用JAVA编写结构化并发应用程序以及Fibers如何帮助扩展应用程序。

我们要解决的问题

想象一下,所有I / O绑定有1万个任务,而每个任务恰好需要100毫秒才能完成。 我们被要求编写高效的代码来完成这些工作。

我们使用下面定义的Job类来模仿我们的工作。

 public class Job { public void doIt() { try { Thread.sleep(100l); } catch (InterruptedException e) { e.printStackTrace(); } }  } 

第一次尝试

在第一次尝试中,我们使用缓存线程池OS线程来编写它

 public class ThreadBasedJobRunner implements JobRunner { @Override public long run(List<Job> jobs) { var start = System.nanoTime(); var executor = Executors.newCachedThreadPool(); for (Job job : jobs) { executor.submit(job::doIt); } executor.shutdown(); try { executor.awaitTermination( 1 , TimeUnit.DAYS); } catch (InterruptedException e) { e.printStackTrace(); Thread.currentThread().interrupt(); } var end = System.nanoTime(); long timeSpentInMS = Util.nanoToMS(end - start);  return timeSpentInMS; }  } 

在此尝试中,我们没有应用Loom项目中的任何内容。 只是一个缓存的线程池,以确保将使用空闲线程,而不是创建新线程。

让我们看看使用此实现可以运行10,000个作业所需的时间。 我使用下面的代码来查找运行速度最快的10个代码。 为简单起见,未使用任何微基准测试工具。

 public class ThreadSleep { public static void main(String[] args) throws InterruptedException { List<Long> timeSpents = new ArrayList<>( 100 ); var jobs = IntStream.range( 0 , 10000 ).mapToObj(n -> new Job()).collect(toList()); for ( int c = 0 ; c <= 100 ; c++) { var jobRunner = new var jobRunner = ThreadBasedJobRunner(); var timeSpent = jobRunner.run(jobs); timeSpents.add(timeSpent); } Collections.sort(timeSpents); System.out.println( "Top 10 executions took:" ); timeSpents.stream().limit( 10 ) .forEach(timeSpent -> System.out.println( "%s ms" .formatted(timeSpent)) ); }  } 

我的机器上的结果是:

执行死刑前10名:
694毫秒
695毫秒 696毫秒 696毫秒 696毫秒 697毫秒 699毫秒 700毫秒 700毫秒 700毫秒

到目前为止,我们有一个代码,在最好的情况下,大约需要700毫秒才能在我的计算机上运行10,000个作业。 让我们这次使用Loom功能实现JobRunner。

第二次尝试(使用光纤)

在使用FibersVirtual Threads的实现中,我还将以结构化方式对并发进行编码。

 public class FiberBasedJobRunner implements JobRunner { @Override public long run(List<Job> jobs) { var start = System.nanoTime(); var factory = Thread.builder().virtual().factory(); try (var executor = Executors.newUnboundedExecutor(factory)) { for (Job job : jobs) { executor.submit(job::doIt); } } var end = System.nanoTime(); long timeSpentInMS = Util.nanoToMS(end - start); return timeSpentInMS; }  } 

也许关于此实现的第一个值得注意的事情是它的简洁性,如果将其与ThreadBasedJobRunner进行比较,您会发现该代码的行数更少! 主要原因是ExecutorService接口中的新更改现在扩展了Autocloseable ,因此,我们可以在try-with-resources范围中使用它。 所有提交的作业完成后,将执行try块之后的代码。

这正是我们用来在JAVA中编写结构化并发代码的主要结构。

上面代码中的另一个新事物是我们构建线程工厂的新方法。 Thread类有一个称为builder的新静态方法,可用于创建ThreadThreadFactory
该行代码正在创建一个创建虚拟线程的线程工厂

 var factory = Thread.builder().virtual().factory(); 

现在,让我们看看使用此实现可以运行10,000个作业所需的时间。

执行死刑前10名:
121毫秒
122毫秒 122毫秒 123毫秒 124毫秒 124毫秒 124毫秒 125毫秒 125毫秒 125毫秒

鉴于Project Loom仍在积极开发中,并且仍有提高速度的空间,但结果确实很棒。
不论是全部还是部分应用,都可以以最小的努力受益于Fibers! 唯一需要更改的是线程池的线程工厂 ,仅此而已!

具体来说,在此示例中,应用程序的运行速度提高了约6倍,但是,速度并不是我们在这里获得的唯一结果!

尽管我不想写有关使用Fibers大大减少了的应用程序的内存占用的信息,但是我强烈建议您在此访问本文的代码,并比较使用的内存量和每个实现占用的OS线程数! 您可以在此处下载Loom的官方早期试用版。

在接下来的帖子中,我将详细介绍Loom引入的其他API项目,以及我们如何将其应用于现实生活中的用例。

请不要犹豫,通过评论与我分享您的反馈意见

翻译自: https://www.javacodegeeks.com/2020/02/openjdk-loom-and-structured-concurrency.html

openjdk8 项目结构

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/331871.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql连库串_数据库连接串整理 - osc_ac5z111b的个人空间 - OSCHINA - 中文开源技术交流社区...

常用JDBC驱动与连接字符串MySQLdriver&#xff1a;com.mysql.jdbc.Driverurl&#xff1a;jdbc:mysql://localhost:3306/mydbMySQL url格式&#xff1a;jdbc:mysql://[host:port]/[database][?参数名1][参数值1][&参数名2][参数值2]…参数名称参数说明缺省值最低版本要求us…

最小生成树——Kruskal(克鲁斯卡尔)算法

【0】README 0.1&#xff09; 本文总结于 数据结构与算法分析&#xff0c; 源代码均为原创&#xff0c; 旨在 理解 Kruskal&#xff08;克鲁斯卡尔&#xff09;算法 的idea 并用 源代码加以实现&#xff1b; 0.2&#xff09;最小生成树的基础知识&#xff0c;参见 http://blo…

java 正则表达式 开头_如何在Java中修复表达式的非法开头

java 正则表达式 开头您是否遇到过这个令人难以置信的错误&#xff0c;想知道如何解决它&#xff1f; 让我们仔细阅读一下&#xff0c;研究如何解决表达式Java非法开头错误。 这是一个动态错误&#xff0c;这意味着编译器会发现某些不符合Java编程规则或语法的内容。 初学者大…

php mysql数据备份命令_MySQL数据备份与恢复的相关操作命令

将mysql安装目录设置到系统环境变量中, 方便在命令行终端直接执行.linux下mysql安装后, root默认密码为空, 可直接执行mysql 登录将mysql安装目录设置到系统环境变量中, 方便在命令行终端直接执行.linux下mysql安装后, root默认密码为空, 可直接执行mysql 登录.正常登录命令mys…

DFS——深度优先搜索基础

【0】README 0.1&#xff09; 本文总结于 数据结构与算法分析&#xff0c; 源代码均为原创&#xff0c; 旨在 review DFS——深度优先搜索 的基础知识&#xff1b; 【1】深度优先搜索的应用 1.1&#xff09;深度优先搜索算法描述&#xff08;转自天勤计算机考研高分笔记——数…

rest post put_REST / HTTP方法:POST与PUT与PATCH

rest post put每个HTTP请求都包含一个方法 &#xff08;有时称为verb &#xff09;&#xff0c;该方法指示对标识的资源执行的操作。 在构建RESTful Web服务时&#xff0c;HTTP方法POST通常用于创建资源&#xff0c;而PUT用于资源更新。 尽管在大多数情况下这很好&#xff0c;…

回归模型的score得分为负_深度研究:回归模型评价指标R2_score

回归模型的性能的评价指标主要有&#xff1a;RMSE(平方根误差)、MAE(平均绝对误差)、MSE(平均平方误差)、R2_score。但是当量纲不同时&#xff0c;RMSE、MAE、MSE难以衡量模型效果好坏。这就需要用到R2_score&#xff0c;实际使用时&#xff0c;会遇到许多问题&#xff0c;今天…

DFS应用——遍历无向图

【0】README 0.1&#xff09; 本文总结于 数据结构与算法分析&#xff0c; 源代码均为原创&#xff0c; 旨在 理解 如何对无向图进行深度优先搜索 的idea 并用源代码加以实现&#xff1b; 0.2&#xff09; 本文还引入了 背向边&#xff08;定义见下文描述&#xff09;&#x…

高效的磁力搜索引擎 -_高效的企业测试-结论(6/6)

高效的磁力搜索引擎 -该系列的最后一部分将涵盖其他端到端测试&#xff0c;生产中的测试以及各部分的结论。 进一步的端到端测试和生产中的测试 除了仅验证单个被测应用程序并模拟外部问题的系统测试之外&#xff0c;我们的管道还必须包括完整的端对端测试&#xff0c;以验证…

linux安装mysql phpmyadmin_ubuntu mysql远程连接+phpmyadmin安装

一、如何让ubuntu上的mysql允许远程连接进入MySQL&#xff0c;执行如下命令:use mysql;GRANT ALL PRIVILEGES ON *.* TO username% IDENTIFIED BY password WITH GRANT OPTION;flush privileges; //刷新select host,user from user; //查看是否成功退出mysql&#xff1b;打开su…

DFS应用——找出无向图的割点

【0】README 0.1&#xff09; 本文总结于 数据结构与算法分析&#xff0c; 源代码均为原创&#xff0c; 旨在 理解 “DFS应用于找割点” 的idea 并用源代码加以实现&#xff1b; 0.2&#xff09; 必须要事先 做个specification的是&#xff1a;对于给定图的除开起始vertex的那…

spock测试_将Spock 1.3测试迁移到Spock 2.0

spock测试了解Spock 2.0 M1&#xff08;基于JUnit 5&#xff09;的期望&#xff0c;如何在Gradle和Maven中迁移到它以及为什么报告发现的问题很重要&#xff1a;&#xff09;。 重要说明 。 我绝对不建议您永久将您的现实项目迁移到Spock 2.0 M1&#xff01; 这是2.x的第一个&…

mysql与jmeter环境变量配置_Java开发技术大杂烩(一)之Redis、Jmeter、MySQL的那些事...

前言毕业答辩告一段落&#xff0c;接下来好好努力工作。Redis遇到的一些问题DENIED Redis is running in protected mode because protected mode is enabled, no bind address was specified, no authentication password is requested to clients. In this mode connections …

DFS应用——寻找欧拉回路

【0】README 0.1&#xff09; 本文总结于 数据结构与算法分析&#xff0c; 源代码均为原创&#xff0c; 旨在 理解 “DFS应用——寻找欧拉回路” 的idea 并用源代码加以实现 &#xff08;源代码&#xff0c;我还没有找到一种有效的数据结构和DFS进行结合&#xff0c;往后会po出…

wiremock 使用_使用WireMock进行更好的集成测试

wiremock 使用无论您是遵循传统的测试金字塔还是采用诸如“ 测试蜂窝”这样的较新方法&#xff0c;都应该在开发过程中的某个时候开始编写集成测试。 您可以编写多种类型的集成测试。 从持久性测试开始&#xff0c;您可以检查组件之间的交互&#xff0c;也可以模拟调用外部服务…

mysql备份七牛云存储_定时备份 Mysql并上传到七牛的方法

多数应用场景下&#xff0c;我们需要对重要数据进行备份、并放置到一个安全的地方&#xff0c;以备不时之需。常见的 MySQL 数据备份方式有&#xff0c;直接打包复制对应的数据库或表文件(物理备份)、mysqldump 全量逻辑备份、xtrabackup 增量逻辑备份等。常见的数据存储方式有…

jetty java_Jetty,Java和OAuth入门

jetty java使用Okta的身份管理平台轻松部署您的应用程序 使用Okta的API在几分钟之内即可对任何应用程序中的用户进行身份验证&#xff0c;管理和保护。 今天尝试Okta。 Jetty是一个小型&#xff0c;高度可扩展的基于Java的Web服务器和servlet引擎。 它支持HTTP / 2&#xff0c…

DFS应用——查找强分支

【0】README 0.1&#xff09; 本文总结于 数据结构与算法分析&#xff0c; 源代码均为原创&#xff0c; 旨在 理解 “DFS应用——查找强分支” 的idea 并用源代码加以实现 &#xff1b; 【1】查找强分支 1.1&#xff09;如何检测一个图是否是强连通的&#xff1a; 通过执行两…

python中的super用法详解_Python中super函数用法实例分析

本文实例讲述了python中super函数用法。分享给大家供大家参考&#xff0c;具体如下&#xff1a;这是个高大上的函数,在python装13手册里面介绍过多使用可显得自己是高手 23333. 但其实他还是很重要的. 简单说, super函数是调用下一个父类(超类)并返回该父类实例的方法. 这里的下…

java 管理多个进程_管理多个Java安装

java 管理多个进程随着越来越多的Java版本发布&#xff0c;在本地环境中管理多个Java安装将变得更加有趣。 不同的项目可能需要不同的Java版本。 jenv项目是管理Java安装的便捷方法。 它可以在全局&#xff0c;目录和外壳程序级别上设置本地Java安装&#xff0c;并使用易于记忆…