- 1、本文档共4页,可阅读全部内容。
- 2、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
- 3、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 4、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
查看更多
【麦子学院】Java 8并行流存在的问题及解决办法详解
IT 在线教育平台———麦子学院:
【麦子学院】Java 8 并行流存在的问题及解决办法详解
对于从事 Java 开发的童鞋来说,相信对于 Java8 的并行流并不陌生,没错,我们常常
用它来执行并行任务,但是由于并行流(parallel stream )采用的是享线程池 ,可能会对
我们的性能造成严重影响,那怎么处理呢?
问题
首先我们来看看具体的问题。在开发中,我们常常通过以下方法,实现并行流执行并
行任务:
myList.parallelStream.map(obj - longRunningOperation())
但是这存在一个严重的问题:在 JVM 的后台,使用通用的 fork/join 池来完成上述功
能,该池是所有并行流共享的。默认情况,fork/join 池会为每个处理器分配一个线程。假
设你有一台 16 核的机器,这样你就只能创建 16 个线程。对 CPU 密集型的任务来说,这
样是有意义的,因为你的机器确实只能执行 16 个线程。但是真实情况下,不是所有的任
务都是 CPU 密集型的。例如:
myList.parallelStream
.map(this::retrieveFromA)
.map(this::processUsingB)
.forEach(this::saveToC)
myList.parallelStream
.map(this::retrieveFromD)
.map(this::processUsingE)
.forEach(this::saveToD)
这两个流很大程度上是受限于 IO 操作,所以会等待其他系统。但这两个流使用相同
的(小)线程池,因此会相互等待而被阻塞,非常不友好。比如:
final ListInteger firstRange = buildIntRange();
firstRange.parallelStream().forEach((number) - {
try {
// do something slow
Thread.sleep(5);
IT 在线教育平台———麦子学院:
} catch (InterruptedException e) { }
});
在执行期间,我获取了一份线程 dump 的文件。这是相关的线程:
ForkJoinPmonPool-worker-1
ForkJoinPmonPool-worker-2
ForkJoinPmonPool-worker-3
ForkJoinPmonPool-worker-4
现在,我要并行的执行这两个并行流:
Runnable firstTask = () - {
firstRange.parallelStream().forEach((number) - {
try {
// do something slow
Thread.sleep(5);
} catch (InterruptedException e) { }
});
};
Runnable secondTask = () - {
secondRange.parallelStream().forEach((number) - {
try {
// do something slow
Thread.sleep(5);
} catch (InterruptedException e) { }
});
};
// run threads
这次我们再看一下线程 dump 文件:
IT 在线教育平台———麦子学院:
ForkJoinPmonPool-worker-1
ForkJoinPmonPool-worker-2
ForkJoinPmonPool-worker-3
ForkJoinPmonPool-worker-4
正如你所见,结果是一样的。我们只使用了 4 个线程。
解决办法
对于上面的问题,我们可以在 JVM 后台使用 fork/join 池,在 ForkJoinTask 的文档中,
我们可以看到:
如果合适,安排一个异步执行的任务到当前正在运行的池中。如果任务不在
inForkJoinPool()中,也可以调用 ForkJoinPmonPool()获取新的池来执行,比如:
ForkJoinPool forkJoinPool = new ForkJoinPool(3);
fo
文档评论(0)