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 项目结构

openjdk8 项目结构_OpenJDK织机和结构化并发相关推荐

  1. OpenJDK织机和结构化并发

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

  2. Python项目实战 —— 01. 疾病预测结构化数据

    Python项目实战 Python项目实战--目录 Python项目实战 -- 01. 疾病预测结构化数据 一.背景 二.解题思路 三.数据分析 3.1 数据清洗 3.2 数据分析 3.2.1 相关系 ...

  3. Atitit 项目的主体设计与结构文档 v5

    Atitit 项目的主体设计与结构文档 v5 1. 版本历史说明2 2. 功能大概说明2 3. 实现的目标3 3.1. cross device跨设备(pc 手机 平板)3 3.2. cross sc ...

  4. .Net项目分层与文件夹结构大全(最佳架子奖,吐槽奖,阴沟翻船奖揭晓)

    .Net项目分层与文件夹结构大全(最佳架子奖,吐槽奖,阴沟翻船奖揭晓) 一个装X的架构师,通过建文件夹就能亮瞎你的狗眼...                                       ...

  5. iOS项目开发过程中的目录结构(转)

    iOS项目开发过程中的目录结构 我在这个目录结构方面真是吃了不少苦,开始总是觉得快点写快点写,后来发现只有快是不行的,在没有给整个项目的结构有一个清楚的认识和了解之前就匆匆动笔(敲代码啦)是非常冒失的 ...

  6. 一位全加器的结构描述vhdl_小学数学结构化学习的评价实践探索

    小学数学结构化学习的评价实践探索 --以<小数意义>为例 小学数学结构化学习是小学生在已有数学知识经验结构基础上,借助教师对小学数学教学内容的整体理解与适切的课程开发,经历个性化的连续.关 ...

  7. [vue] 说下你的vue项目的目录结构,如果是大型项目你该怎么划分结构和划分组件呢?

    [vue] 说下你的vue项目的目录结构,如果是大型项目你该怎么划分结构和划分组件呢? views目录存放一级路由的组件,即视图组件 Components目录存放组件 Store存放vuex相关文件 ...

  8. 【数理逻辑】命题逻辑 ( 命题逻辑推理 | 推理的形式结构 | 推理定律 | 附加律 | 化简律 | 假言推理 | 拒取式 | 析取三段论 | 假言三段论 | 等价三段论 | 构造性两难 )

    文章目录 一.推理的形式结构 二.推理定律 1.附加律 2.化简律 3.假言推理 4.拒取式 5.析取三段论 6.假言三段论 7.等价三段论 8.构造性两难 一.推理的形式结构 推理的形式结构 前提 ...

  9. iOS结构化并发---喵神出品。

    前言 学如逆水行舟,不进则退.共勉!! async/await 所引入的异步函数的简单写法,可以在暂停点时放弃线程,这是构建高并发系统所不可或缺的.但是异步函数本身,其实并没有解决并发编程的问题.结构 ...

最新文章

  1. 仅需6步,教你轻易撕掉app开发框架的神秘面纱(5):数据持久化
  2. AcWing 2983. 玩具 / POJ 2318.toys(计算几何基础、二分、判断点和直线的位置关系)
  3. Facebook欧盟垄断案陷入灰色地带 立法或调整
  4. 《OpenStack云计算实战手册(第2版)》——1.7 添加用户
  5. 保存blob为本地文件
  6. Android编程之如何取得View的当前位置
  7. 阶段1 语言基础+高级_1-3-Java语言高级_09-基础加强_第2节 反射_6_反射_获取字节码Class对象的三种方式...
  8. 电感式传感器工作原理与电感式传感器应用案例-博扬智能
  9. 在线预览 PDF 文档插件 PDFObject.js
  10. ISIS 协议 概述
  11. Deecamp考试给我的启发
  12. android studio scala插件,在Android Studio中使用Scala和Java
  13. 【初学者知识】了解一下BASIC语言
  14. react项目实战五 个人中心页面
  15. 机器学习自然语言处理之英文NLTK(代码+原理)
  16. 江歌和王昌龄 论程序猿的职场情商
  17. win11英文版安装中文输入法中文语言包切换到中文版
  18. 汇编语言笔记(10)CALL和RET指令
  19. ESP8266开发板
  20. 图片柱面投影简单实现

热门文章

  1. [CQOI2018] 交错序列(矩阵加速优化dp)
  2. [NowCoder牛客]2021NOIP提高组模拟赛第二场T3——树数树(启发式合并堆)
  3. 线性代数问卷调查反馈——Find The Determinant III,Takahashi‘s Basics in Education and Learning
  4. 【2020牛客NOIP赛前集训营-提高组(第二场)】题解(GCD,包含,前缀,移动)
  5. P7137-[THUPC2021 初赛]切切糕【dp】
  6. 2020牛客NOIP赛前集训营提高组(第四场)B-色球【链表】
  7. 纪念中学15-5(=10)天感想
  8. 【双指针】Square Pasture G(P7153)
  9. 成为更优秀的程序员:退后一步看问题
  10. Java编程:Java的反射机制中的 getComponentType() 方法