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。
第二次尝试(使用光纤)
在使用Fibers或Virtual 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的新静态方法,可用于创建Thread或ThreadFactory 。
该行代码正在创建一个创建虚拟线程的线程工厂。
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 项目结构
openjdk8 项目结构_OpenJDK织机和结构化并发相关推荐
- OpenJDK织机和结构化并发
Project Loom是Hotspot Group赞助的项目之一,旨在向JAVA世界提供高吞吐量和轻量级的并发模型. 在撰写本文时,Loom项目仍处于积极开发中,其API可能会更改. 为什么要织机? ...
- Python项目实战 —— 01. 疾病预测结构化数据
Python项目实战 Python项目实战--目录 Python项目实战 -- 01. 疾病预测结构化数据 一.背景 二.解题思路 三.数据分析 3.1 数据清洗 3.2 数据分析 3.2.1 相关系 ...
- Atitit 项目的主体设计与结构文档 v5
Atitit 项目的主体设计与结构文档 v5 1. 版本历史说明2 2. 功能大概说明2 3. 实现的目标3 3.1. cross device跨设备(pc 手机 平板)3 3.2. cross sc ...
- .Net项目分层与文件夹结构大全(最佳架子奖,吐槽奖,阴沟翻船奖揭晓)
.Net项目分层与文件夹结构大全(最佳架子奖,吐槽奖,阴沟翻船奖揭晓) 一个装X的架构师,通过建文件夹就能亮瞎你的狗眼... ...
- iOS项目开发过程中的目录结构(转)
iOS项目开发过程中的目录结构 我在这个目录结构方面真是吃了不少苦,开始总是觉得快点写快点写,后来发现只有快是不行的,在没有给整个项目的结构有一个清楚的认识和了解之前就匆匆动笔(敲代码啦)是非常冒失的 ...
- 一位全加器的结构描述vhdl_小学数学结构化学习的评价实践探索
小学数学结构化学习的评价实践探索 --以<小数意义>为例 小学数学结构化学习是小学生在已有数学知识经验结构基础上,借助教师对小学数学教学内容的整体理解与适切的课程开发,经历个性化的连续.关 ...
- [vue] 说下你的vue项目的目录结构,如果是大型项目你该怎么划分结构和划分组件呢?
[vue] 说下你的vue项目的目录结构,如果是大型项目你该怎么划分结构和划分组件呢? views目录存放一级路由的组件,即视图组件 Components目录存放组件 Store存放vuex相关文件 ...
- 【数理逻辑】命题逻辑 ( 命题逻辑推理 | 推理的形式结构 | 推理定律 | 附加律 | 化简律 | 假言推理 | 拒取式 | 析取三段论 | 假言三段论 | 等价三段论 | 构造性两难 )
文章目录 一.推理的形式结构 二.推理定律 1.附加律 2.化简律 3.假言推理 4.拒取式 5.析取三段论 6.假言三段论 7.等价三段论 8.构造性两难 一.推理的形式结构 推理的形式结构 前提 ...
- iOS结构化并发---喵神出品。
前言 学如逆水行舟,不进则退.共勉!! async/await 所引入的异步函数的简单写法,可以在暂停点时放弃线程,这是构建高并发系统所不可或缺的.但是异步函数本身,其实并没有解决并发编程的问题.结构 ...
最新文章
- 仅需6步,教你轻易撕掉app开发框架的神秘面纱(5):数据持久化
- AcWing 2983. 玩具 / POJ 2318.toys(计算几何基础、二分、判断点和直线的位置关系)
- Facebook欧盟垄断案陷入灰色地带 立法或调整
- 《OpenStack云计算实战手册(第2版)》——1.7 添加用户
- 保存blob为本地文件
- Android编程之如何取得View的当前位置
- 阶段1 语言基础+高级_1-3-Java语言高级_09-基础加强_第2节 反射_6_反射_获取字节码Class对象的三种方式...
- 电感式传感器工作原理与电感式传感器应用案例-博扬智能
- 在线预览 PDF 文档插件 PDFObject.js
- ISIS 协议 概述
- Deecamp考试给我的启发
- android studio scala插件,在Android Studio中使用Scala和Java
- 【初学者知识】了解一下BASIC语言
- react项目实战五 个人中心页面
- 机器学习自然语言处理之英文NLTK(代码+原理)
- 江歌和王昌龄 论程序猿的职场情商
- win11英文版安装中文输入法中文语言包切换到中文版
- 汇编语言笔记(10)CALL和RET指令
- ESP8266开发板
- 图片柱面投影简单实现
热门文章
- [CQOI2018] 交错序列(矩阵加速优化dp)
- [NowCoder牛客]2021NOIP提高组模拟赛第二场T3——树数树(启发式合并堆)
- 线性代数问卷调查反馈——Find The Determinant III,Takahashi‘s Basics in Education and Learning
- 【2020牛客NOIP赛前集训营-提高组(第二场)】题解(GCD,包含,前缀,移动)
- P7137-[THUPC2021 初赛]切切糕【dp】
- 2020牛客NOIP赛前集训营提高组(第四场)B-色球【链表】
- 纪念中学15-5(=10)天感想
- 【双指针】Square Pasture G(P7153)
- 成为更优秀的程序员:退后一步看问题
- Java编程:Java的反射机制中的 getComponentType() 方法