博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
并行流使用注意事项
阅读量:3964 次
发布时间:2019-05-24

本文共 2789 字,大约阅读时间需要 9 分钟。

一、FolkJoinPool

JDK 7引入了新的线程池FolkJoinPool,它使用了一个无限队列来保存需要执行的任务,而线程的数量则是通过构造函数传入,如果没有向构造函数中传入希望的线程数量,那么当前计算机可用的CPU数量会被设置为线程数量作为默认值。

//获取CPU核心Runtime.getRuntime().availableProcessors();

这个线程的工作核心主要是两个:一个是分治思想,一个是工作窃取

分治思想
每个任务都只fork出两个子任务,如果负责fork子任务的当前任务不做任何事情,那么最终将只有叶子节点真正做事情,其它节点都只是负责fork子任务与合并结果
在这里插入图片描述
|

工作窃取:一个大的任务切分出的子任务会提交到线程池的任务队列中,4个线程从任务队列中获取任务执行,哪个线程执行的任务快,哪个线程执行的任务就多,只有队列中没有任务线程才是空闲的,这就是工作窃取。

适合场景:使用ForkJoinPool能够使用数量有限的线程来完成非常多的具有父子关系的任务

注意问题 :ForkJoinPool在执行过程中,会创建大量的子任务,堆内存和垃圾回收不友好

二、并行流Parallel Stream

并行流也是使用的ForkJoinPool的,但默认线程数量只能是CPU的核心数量,可以通过以下方式更改。

//修改并行流使用的ForkJoinPool的线程数量为12System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism","12");

但是,笔者不建议这样,因为并行流使用的FolkJoinPool是整个JVM进程全局唯一的线程池,如果改了,虽然对你当前的业务逻辑来说,算是调优了,但对于项目中其它地方只是用来做非耗时的并行流运算,性能就差了。

我们可以验证是否并行流使用的FolkJoinPool是全局唯一的线程池。

List
list = new ArrayList<>(100);for (int i = 1; i <= 50; i++) {
new Thread("test-" + i) {
String currentThreaName = this.getName(); @Override public void run() {
list.parallelStream() .forEach(numbser -> {
Thread c = Thread.currentThread(); System.out.println(currentThreaName + "===> " + c.getClass().getName() + ":" + c.getName() + ":" + c.getId()); try {
Thread.sleep(10); } catch (InterruptedException e) {
e.printStackTrace(); } }); } }.start();}Thread.sleep(Integer.MAX_VALUE);

我们创建了50个线程,jvm启动后自身也会创建一些线程,比如gc线程,但实际运行结果如下:

test-2===> java.util.concurrent.ForkJoinWorkerThread:ForkJoinPool.commonPool-worker-3:65test-14===> java.util.concurrent.ForkJoinWorkerThread:ForkJoinPool.commonPool-worker-1:63test-14===> java.util.concurrent.ForkJoinWorkerThread:ForkJoinPool.commonPool-worker-2:64test-2===> java.util.concurrent.ForkJoinWorkerThread:ForkJoinPool.commonPool-worker-3:65test-14===> java.util.concurrent.ForkJoinWorkerThread:ForkJoinPool.commonPool-worker-2:64test-14===> java.util.concurrent.ForkJoinWorkerThread:ForkJoinPool.commonPool-worker-1:63test-2===> java.util.concurrent.ForkJoinWorkerThread:ForkJoinPool.commonPool-worker-3:65test-14===> java.util.concurrent.ForkJoinWorkerThread:ForkJoinPool.commonPool-worker-1:63test-14===> java.util.concurrent.ForkJoinWorkerThread:ForkJoinPool.commonPool-worker-2:64test-2===> java.util.concurrent.ForkJoinWorkerThread:ForkJoinPool.commonPool-worker-3:65

很明显,即使我们并行的再多,在FrokJoinPool也只有两三个线程,导致很多请求争抢线程执行任务,发生阻塞,超时。

三、并行流Parallel Stream使用注意情况

1、请不要乱用并行流,在使用之前要考虑清楚任务是否耗时,有I/O操作的一定不要使用并行流

2、并行流针对的是一些计算量大的cpu密集型的任务

3、对于循环,尽量不要使用stream或Parallel Stream,因为创建流的过程内部要起很多的对象并Folk线程,这很耗时,得不偿失

参考文章:

转载地址:http://itgzi.baihongyu.com/

你可能感兴趣的文章
64位int类型用printf输出问题
查看>>
网络后台开发面试题目
查看>>
进程的状态转换
查看>>
如何查看进程的信息(线程数)
查看>>
Linux中的chage命令
查看>>
linux-详细解析密码文件passwd与shadow
查看>>
su- 与su的区别
查看>>
linux下发邮件mail
查看>>
echo如何手动输出换行
查看>>
身份证的正确使用方法——非常重要的知识
查看>>
ExtJS & Ajax
查看>>
Tomcat在Windows下的免安装配置
查看>>
JMeter常用测试元件
查看>>
JMeter——使用技巧
查看>>
Hibernate 实体层设计--Table per subclass
查看>>
Ruby解决方案:The 'ffi' native gem requires installed build tools ; 含最新DevKit下载地址
查看>>
Python之操作MySQL数据库(二)
查看>>
简单介绍如何使用robotium进行自动化测试
查看>>
Python之操作XML文件
查看>>
eclipse+ADT 进行android应用签名详解
查看>>