`
deepinmind
  • 浏览: 456237 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
1dc14e59-7bdf-33ab-841a-02d087aed982
Java函数式编程
浏览量:42016
社区版块
存档分类
最新评论

Java 8与availableProcessors()续

阅读更多

接上文Java 8与Runtime.getRuntime().availableProcessors().

通用池的并发数一般都是availableProcessors() - 1,除非我们通过系统属性指定了它的值。然而,如果你在一个单核的机器上运行Java的话,你会把这个通用池的并发数设置成1,更准确的值其实应该是0。你可能会想,地球上还有谁有单核的机器?事实上,现在给开发人员提供共享的虚拟开发环境已经越来越普遍了,这种通常都是配备单核CPU,但内存会很大。在虚拟机里,单核并不是什么稀奇事。问题在于像parallelSort这样的代码试图去以并行的方式来进行排序,而不是传统的老的排序机制。在Arrays.parallelSort() 方法中,它会去查看 ForkJoinPool.getCommonPoolParallelism()的值。由于在单核和双核的机器上这个值都是1,它会调用默认的Arrays.sort()方法。因此我认为说在双核机器上能有30%的性能提升的说法是扯淡的。

然而,对并行流来说情况会好些。由于在双核系统里,有一个大小为1的 Fork/Join池,实际上我们有两个线程在工作:1,线程池里的线程,2,提交任务的线程。这里我犯了个很常见的错误,就是让我统计教室里有多少人时我忘了把我自己算进去 了。其实parallel()还是有效果的,多多少少吧。根据availableProcessors()返回的值可以创建出合适数量的工作线程。除了在单核的机器上,因为这会使用两个线程而不是和物理处理器数对应的一个线程。

Pierre-yves Saumont给我发过来一份代码,这能证明parallel()默认是使用availableProcessors()返回的值(注:而不是availableProcessors()-1)。



import java.util.*;
import java.util.concurrent.*;
import java.util.stream.*;

public class CountThreads {
  private static Map<String, Integer> map = new ConcurrentHashMap<>();

  public static void main(String... args) {
    System.out.println(IntStream.range(1, 1_000_000).
        parallel().filter(CountThreads::isPrime).count());
    map.forEach((k, v) -> System.out.println(k + ": " + v));
  }

  public static boolean isPrime(int n) {
    map.compute(Thread.currentThread().getName(),
        (k, v) -> v == null ? 1 : v + 1);
    if (n % 2 == 0) return false;
    for (int i = 3; i * i <= n; i += 2) {
      if (n % i == 0) {
        return false;
      }
    }
    return true;
  }
}
 



在一台双核以及单核的机器 上,可以看到下面的输出:

78498
ForkJoinPool.commonPool-worker-1: 499999
main: 500000
 




在我的1-4-2机器上,有8个超线程,我们可以看到有8个线程在工作:

78498
ForkJoinPool.commonPool-worker-7: 125000
ForkJoinPool.commonPool-worker-1: 125000
ForkJoinPool.commonPool-worker-2: 125000
main: 125000
ForkJoinPool.commonPool-worker-5: 125000
ForkJoinPool.commonPool-worker-6: 156249
ForkJoinPool.commonPool-worker-3: 125000
ForkJoinPool.commonPool-worker-4: 93750
 



如果你想测试类似并行排序的性能,这需要大量的内存访问,你可能会发现你的超线程能提供接近线性的性能提升。这是由于最大的瓶颈在于填充缓存行的速度。超线程能允许它并行地执行。查找素数对内存的依赖不多,因此物理核数的增加可能对性能的提升并不大。

除此之外,parallelSort()排序的算法可能有些不同。我测试的一些特定的数据集下,单线程的Arrays.sort()比8线程的Arrays.paralleclSort()的还要快,尤其是当数据集已经排好序的情况下。

最后,我用Fork/Join框架写了一段CountThreads的代码。它大概是这样的:

import java.util.concurrent.*;

public class CountThreadsForkJoin {
  public static void main(String... args) {
    System.out.println(ForkJoinPool.commonPool().invoke(
        new PrimeSearcher(1, 1_000_000)));
  }

  private static class PrimeSearcher extends RecursiveTask<Integer> {
    private static final int THRESHOLD = 10000;
    private final int from;
    private final int to;

    public PrimeSearcher(int from, int to) {
      this.from = from;
      this.to = to;
    }

    protected Integer compute() {
      if (to - from < THRESHOLD) {
        return serialCount();
      }
      int from0 = from;
      int to0 = from + (to - from) / 2;
      int from1 = to0 + 1;
      int to1 = to;
      PrimeSearcher ps0 = new PrimeSearcher(from0, to0);
      PrimeSearcher ps1 = new PrimeSearcher(from1, to1);
      ps0.fork();
      return ps1.invoke() + ps0.join();
    }

    private Integer serialCount() {
      int count = 0;
      for (int i = from; i < to; i++) {
        if (CountThreads.isPrime(i)) count++;
      }
      return count;
    }
  }
}
 




有人觉得Java 8的并行流需要手动写 Fork/Join,这个算不上什么提高,我倒是想去会会他们。

import java.util.stream.*;

public class CountThreadsStream {
  public static void main(String... args) {
    System.out.println(IntStream.range(1, 1_000_000).
        parallel().filter(CountThreads::isPrime).count());
  }
}
 




时间会告诉你现实中parallel()究竟会有多少用处。


原创文章转载请注明出处:http://it.deepinmind.com

英文原文链接
1
0
分享到:
评论

相关推荐

    详解Java8与Runtime.getRuntime().availableProcessors()

    在Java 8中,`Runtime.getRuntime().availableProcessors()`是一个重要的方法,用于获取当前系统可用的处理器核心数量。这个信息对于优化多线程程序,尤其是使用并行处理的场景至关重要,例如Java 8引入的并行流...

    Java8API文档(官方离线版)

    Java 8 API是Java开发的重要参考资料,它包含了Java 8版本的所有公共类、接口和...这个官方离线版的文档是每一个Java 8开发者必备的参考资料,它详尽地阐述了每个类和接口的功能与用法,有助于开发者快速查询和学习。

    JAVA8API-官方文档下载-中文版

    **JAVA8 API 中文官方文档概述** JAVA8 API 是Java开发者的重要参考资料,它详细阐述了Java 8平台的核心类库,包括各种接口、类、枚举和注解等。这份中文版的官方文档使得国内开发者能够更加方便地理解和使用Java 8...

    java 8 安装包

    4. **日期与时间API的改进**:Java 8引入了全新的java.time包,提供了更强大、易用的日期和时间API,取代了过时的java.util.Date和java.util.Calendar。 5. **Stream API**:这是一个强大的新工具,允许对集合进行...

    java大文件分块上传断点续传demo

    8. 测试与调试:包括单元测试、集成测试,确保各个部分的功能正确无误。 这个"java大文件分块上传断点续传demo"是一个完整的解决方案,可以直接在Eclipse中运行和测试。导入项目后,可以通过阅读源代码,理解其实现...

    java jdk 8 帮助文档 中文 文档 chm 谷歌翻译

    JDK1.8 API 中文谷歌翻译版 java帮助文档 JDK API java 帮助文档 谷歌翻译 JDK1.8 API 中文 谷歌翻译版 java帮助文档 Java最新帮助文档 本帮助文档是使用谷歌翻译,非人工翻译。准确性不能保证,请与英文版配合使用 ...

    java实现断点续传

    断点续传内核的实现 主要用了 6 个类,包括一个测试类。 SiteFileFetch.java 负责整个文件的抓取,控制内部线程 (FileSplitterFetch 类 )。 FileSplitterFetch.java 负责部分文件的抓取。 FileAccess.java 负责...

    java-jdk-8u51-windows-x64.exe.zip

    Java JDK 8u51是Oracle公司发布的一个针对Windows x64操作系统的64位Java开发工具包。这个版本在2015年7月20日被标记为最新的,对于开发者来说,它是构建和运行Java应用程序的基础。下面将详细阐述Java JDK 8u51的...

    windows系统Java JDK8安装包

    Java JDK(Java Development Kit)是开发和运行Java应用程序的基础,对于Windows系统来说,JDK8是许多开发者常用的一个版本。这个压缩包包含了Windows系统下的Java JDK8安装程序,即`jdk-8u321-windows-x64.exe`,它...

    Java-JDK-11.0.8(Windows &amp;amp; Mac os) 下载

    Java JDK 11.0.8 是Oracle公司发布的Java开发工具包的一个稳定版本,它针对开发者提供了完整的编译、调试和运行Java应用程序所需的环境。这个版本支持Windows和Mac OS操作系统,使得不同平台上的开发者都能方便地...

    socket做的支持多线程断点上传or断点续传Java源码

    标题中的“socket做的支持多线程断点上传or断点续传Java源码”涉及到的是在网络编程中,如何使用Java的Socket API实现一个能够处理断点上传和断点续传功能的服务。这是一个高级的网络编程任务,通常在大型文件传输...

    Java多线程与线程安全实践-基于Http协议的断点续传

    Java多线程与线程安全实践-基于Http协议的断点续传 Java多线程与线程安全实践-基于Http协议的断点续传 Java多线程与线程安全实践-基于Http协议的断点续传 Java多线程与线程安全实践-基于Http协议的断点续传 Java多...

    Java SE 8 Documentation.chm

    Java SE 8是Java开发的重要版本,带来了许多创新特性,极大地提升了开发效率和代码质量。这份"Java SE 8 Documentation.chm"文件是官方提供的完整Java 8 API文档,是开发者学习和查阅Java 8特性的必备参考资料。CHM...

    JAVA多线程与线程安全实践-基于Http协议的断点续传.rar

    JAVA多线程与线程安全实践-基于Http协议的断点续传 JAVA多线程与线程安全实践-基于Http协议的断点续传 JAVA多线程与线程安全实践-基于Http协议的断点续传 JAVA多线程与线程安全实践-基于Http协议的断点续传 JAVA多...

    Java多线程与线程安全实践-基于Http协议的断点续传.zip

    Java多线程与线程安全实践-基于Http协议的断点续传Java多线程与线程安全实践-基于Http协议的断点续传Java多线程与线程安全实践-基于Http协议的断点续传Java多线程与线程安全实践-基于Http协议的断点续传Java多线程与...

    jdk1.8.0_144 (Java SE Development Kit 8u144)

    8. ** Nashorn JavaScript引擎**:Java 8引入了Nashorn JavaScript引擎,允许Java代码直接执行JavaScript,实现了Java与JavaScript的互操作。 **三、JDK 1.8.0_144对Mac用户的意义** 对于使用Mac系统的开发者,...

    java 文件上传下载 断点续传 断点上传

    本项目提供了两种实现方式,一种是基于Web端的上传下载,另一种是通过Java接口实现的断点续传上传。 1. **Web端上传下载**: - 这种方法通常涉及到HTTP协议,使用HTML表单或者AJAX技术。用户通过Web页面选择本地...

    java jdk-8u51-windows-i586.exe

    Java JDK 8u51是Java Development Kit的一个特定版本,主要针对Windows操作系统,特别是i586架构,也就是32位系统。然而,这个版本也兼容64位系统,为那些在64位环境中开发Java应用程序的用户提供支持。Java JDK是...

    java jdk-8u60-windows-x64

    Java JDK 8u60是Oracle公司为Windows 64位操作系统发布的Java开发工具包的特定版本,截至2015年9月8日,它是该平台上的最新更新。Java Development Kit (JDK) 是Java编程语言的核心组件,用于开发和运行Java应用程序...

    Java实现多线程下载和断点续传

    1. 把每个下载文件切成若干个块(Block),然后得到一个位图,用来标记每个块的下载情况,并保存到文件里,用于实现断点续传。 2. HTTP Header里增加Range,如果服务器返回Cotent-Range 说明服务器支持文件定位,可以...

Global site tag (gtag.js) - Google Analytics