gpt4 book ai didi

java - Java 8 Collections并发处理

转载 作者:行者123 更新时间:2023-12-02 08:24:39 25 4
gpt4 key购买 nike

我打算在公司内部就Java 8的新功能和概念进行演讲。

我想重点介绍新集合库的并行处理功能。

无论我在哪里阅读有关的Java 8 以及对集合库使用更多功能样式迭代器的需求,都提到这将有助于利用当今很正常的多核服务器。但是很少有人提到这是如何实现的,以及这是否是一个普遍的真理,更不用说任何性能基准了。

因为即使我公司中经验丰富的开发人员声称了解线程,也不知道较低级别的实际线程是如何工作的,所以我正在尝试收集这一方面的知识。基于阅读多个博客等内容,我提出了以下一系列主张。

对于以下几点(true/false) ..我会提供一些反馈,我将不胜感激。

  • 线程是操作系统中最低的调度单元(是的,但并不是所有的应用程序程序员都知道;-))
  • 单线程程序一次只能在一个内核上运行。因此,在四核CPU中,例如,未使用75%的CPU。
  • 当前Java集合迭代器的问题在于,它是一个外部迭代器,并且不可能(至少是开箱即用)将庞大的集合迭代分布到多个线程中。新的集合库操作使并发成为可能,而无需处理低级并发问题
  • Java 8使使用增强的集合库可以使用内部迭代器并行化迭代成为可能

    代替Java 7
    for (Shape s : shapes) {if (s.getColor() == RED)s.setColor(BLUE); }
    我们在Java 8中
    shapes.forEach(s -> {
    if (s.getColor() == RED)
    s.setColor(BLUE); })
  • 但是为了并行化以上迭代,必须显式使用parallel()Stream API方法
    private static void printUsingCoolLambda (final List<String> names) {
    names.parallelStream().forEach(s -> System.out.println(s));
    System.out.println("Printed using printUsingCoolLambda");
    }

    但是即使那样也不能保证操作将并行完成,因为parallelStream()的Javadoc表示以下"Returns a possibly parallel {@code Stream} with this collection as its source. It is allowable for this method to return a sequential stream"
  • 最终,不能保证所有内核都将被利用,因为线程调度不是JVM的责任,而是由OS规定的。

  • 编辑

    我最难获得正确的第5点和第6点。正如各种Java 8博客所说的那样:“使用这个新的parallelStream(),您将获得开箱即用的并行处理功能(免费,并且您作为应用程序程序员无需担心这一点)”,我的问题只用了一句话会一直是 吗,那么一直都是正确的吗?

    最佳答案

    I would be thankful for some feedback for the following points (true/false)..



    不幸的是,答案都不是对还是错。它们都是“取决于”或“很复杂”的。 :-)

    1: A thread is the lowest unit of scheduling in an OS.



    基本上是这样。 OS调度线程,并且Java线程在大多数情况下对应于OS线程。

    但是,这个故事还有更多。我鼓励您不要过多地考虑线程。它们是用于构建并行应用程序的非常低级的构造。

    当然,可以使用线程编写应用程序,但是通常更优选使用更高级别的构造。一个这样的构造就是 任务,它是特定于应用程序的工作块。如果您可以将工作负载划分为单独的任务,则可以将这些任务提交到 Executor,该文件将管理任务在线程上的调度以及线程的创建和销毁。这是Java SE 5中的 java.util.concurrent内容。

    构建并行应用程序的另一种方法是使用 数据并行性。 Java SE 7引入了Fork-Join框架。这是指不是分派(dispatch)线程,而是分派(dispatch)任务,特别是表示数据的递归可拆分部分的任务。 FJ框架对于某些工作负载非常有效,但是任务的拆分和合并是程序员的责任,这可能会很麻烦。

    Java SE 8中的新功能是stream API,它以更方便的方式支持数据并行性。

    我从您有关线程的问题中推断出很多内容,但是您的问题似乎集中在线程上,而并行性比线程要多得多。 (我的一位同事最近说,“线程是个虚假的上帝。”)

    2: A single threaded program can run only on one core at a time. So in a quad core CPU, 75% of the CPU is not utilized for example.



    大多是真的。如果仅考虑应用程序线程,则单个线程永远不能使用超过四核CPU的25%。但是,如果您考虑在JVM中运行Java线程,那么即使是单线程Java应用程序在多核系统上的运行速度也可能比在单核系统上快。原因是像垃圾回收器这样的JVM服务线程可以与多核系统上的应用程序线程并行运行,而它们必须抢占单核系统上的应用程序线程。

    3: The problem with present Java collection iterator is that it is an external iterator and it is not possible (at least out of the box) to distribute a bulky collection iteration to multiple threads. The new collection library operations makes it possible to have concurrency without having the need to deal with low level concurrency issues.



    通常是的。外部迭代和内部迭代是概念。外部迭代由实际的 Iterator接口(interface)实现。内部迭代可能使用 Iterator,简单的for循环,一组fork-join任务或其他方法。

    它不是新的集合库,而是Java 8中的新Streams API将提供一种更方便的方式来跨线程分配工作。

    4: Java 8 makes it possible using an enhanced collection library to parallellize iteration using an internal iterator (... shapes.forEach example ...)



    关闭。同样,提供便利的并行性的是新的Streams库(而不是集合)。没有什么像 Collection.parallelForEach一样。要并行处理集合的元素,必须从中拉出并行流。 java.util.Arrays类中的数组也有多种并行操作。

    5: But in order to parallelize the above iteration, one must explicitly use the parallel method of the Stream API .... But even then there is no guarantee that the operation will be done in parallel.



    正确,您需要使用 parallelparallelStream方法请求并行性,具体取决于您是从流还是集合开始。

    当然,关于没有任何保证,生命中永远不会有任何保证。 :-)毕竟,如果您在单核系统上运行,则无法并行运行。另一种情况是,在applet中,安全管理器可能禁止应用程序使用多个线程。实际上,在大多数环境中,请求并行流确实会分散工作负载并并行运行任务。默认情况下,这些任务在 common fork-join pool中运行,它的默认线程数与系统中的内核数相同。但是有人可能将线程数设置为其他数,甚至设置为1,这是API本身无法提供任何保证的原因之一。

    6: Ultimately, there is no guarantee that all the cores will be utilized as thread scheduling is NOT a JVM responsibility, rather dictated by OS. ... As various Java 8 blogs says just that "use this new parallelStream() and you will get parallel processing out of the box (for free and you as an application programmer are freed from having to worry about that)", my question in one sentence would have been is that really correct all the time?



    如上所述,没有任何保证。系统中有许多层次,事物可以向左转。即使您的公共(public)FJ池具有与内核一样多的线程,也不能保证每个Java线程都有自己的OS线程。 (在Hotspot JVM中,我认为这始终是正确的。这取决于JVM。)在同一系统上,可能还有其他进程(甚至其他JVM)在争用内核,因此您的应用程序可能没有那么多内核你想要。从这种意义上说,JVM只能由OS来为其调度线程。

    我不确定该博客条目来自何处,但是有关“免费”并行处理和“您不必担心”的观点有点过头了。实际上,这基本上是错误的。

    的确,与使用早期的API相比,可以更方便地编写并行流。但是也有可能将其弄得非常非常错误。如果将副作用放入流管道中,则会出现竞争状况,并且每次都可能会得到不同的错误答案。或者,即使您注意在副作用之间进行同步,也可能会创建足够的争用,因此并行流的运行速度可能比顺序流的运行速度还要慢。

    即使您设法避免了这些陷阱,在N核系统上运行并行流也不会使您的N倍加速。就是那样行不通。对于较小的工作负载,拆分和合并并行任务的开销占主导地位,这可能导致计算比顺序任务慢。对于较大的工作负载,并行加速可以抵消开销,但是开销仍然存在。加速的数量还取决于工作负载的性质,拆分特征,数据的块状性等。调整并行应用程序是一件黑手艺。

    根据我的经验,对于易于并行化的工作负载,最大化两核系统非常容易。四核系统通常至少可以提高3倍的速度。有了更多的内核,获得5到6倍的加速并不是很困难,但是要达到这个速度则需要实际工作。

    对于不太容易并行化的工作负载,您甚至必须尝试并行运行它之前,必须对应用程序进行大量思考和重组。

    我不会说Java 8为您提供了“免费”或“无需担心”之类的并行性。我想说Java 8使您有机会比以前更方便地编写并行程序。但是您仍然必须努力使其正确,并且可能仍需要努力实现所需的加速。

    关于java - Java 8 Collections并发处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21786548/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com