国企网站建设标准,自己怎么创建网站,网站上的二维码怎么做的,canvas做的网站openjdk8 项目结构Project Loom是Hotspot Group赞助的项目之一#xff0c;旨在向JAVA世界提供高吞吐量和轻量级的并发模型。 在撰写本文时#xff0c;Loom项目仍在积极开发中#xff0c;其API可能会更改。 为什么要织机#xff1f; 每个新项目可能会出现的第一个问题是为什… 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(ListJob 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 { ListLong 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(ListJob 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.htmlopenjdk8 项目结构