网易首页 > 网易号 > 正文 申请入驻

parallelStream的坑,不踩不知道,一踩吓一跳

0
分享至

不羡鸳鸯不羡仙,一行代码调半天。原创:小姐姐味道(微信公众号ID:xjjdog),欢迎分享,转载请保留出处。

  很多同学喜欢使用lambda表达式,它允许你定义短小精悍的函数,体现你高超的编码水平。当然,这个功能在某些以代码行数来衡量工作量的公司来说,就比较吃亏一些。

  比如下面的代码片段,让人阅读的时候就像是读诗一样。但是一旦用不好,也是会要命的。

  List transactionsIds =
widgets.stream()
.filter(b -> b.getColor() == RED)
.sorted((x,y) -> x.getWeight() - y.getWeight())
.mapToInt(Widget::getWeight)
.sum();

  这段代码有一个关键的函数,那就是stream。通过它,可以将一个普通的list,转化为流,然后就可以使用类似于管道的方式对list进行操作。总之,用过的都说好。

  对这些函数还不是太熟悉?可以参考:

  问题来了

  假如我们把stream换成parallelStream,会发生什么情况?

  根据字面上的意思,流会从串行变成并行

  既然是并行,那用屁股想一想,就知道这里面肯定会有线程安全问题。不过我们这里讨论的并不是要你使用线程安全的集合,这个话题太低级。现阶段,知道在线程不安全的环境中使用线程安全的集合,已经是一个基本的技能。

  这次踩坑的地方,是并行流的性能问题。

  我们用代码来说话。

  下面的代码,开启了8个线程,这8个线程都在使用并行流进行数据计算。在执行的逻辑中,我们让每个任务都sleep 1秒钟,这样就能够模拟一些I/O请求的耗时等待。

  使用stream,程序会在30秒后返回,但我们期望程序能够在1秒多返回,因为它是并行流,得对得起这个称号。

  测试发现,我们等了好久,任务才执行完毕。

  static void paralleTest() {
List numbers = Arrays.asList(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29
);
final long begin = System.currentTimeMillis();
numbers.parallelStream().map(k -> {
try {
Thread.sleep(1000);
System.out.println((System.currentTimeMillis() - begin) + "ms => " + k + " \t" + Thread.currentThread());
} catch (InterruptedException e) {
e.printStackTrace();
}
return k;
}).collect(Collectors.toList());
}

  public static void main(String[] args) {
// System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "20");
new Thread(() -> paralleTest()).start();
new Thread(() -> paralleTest()).start();
new Thread(() -> paralleTest()).start();
new Thread(() -> paralleTest()).start();
new Thread(() -> paralleTest()).start();
new Thread(() -> paralleTest()).start();
new Thread(() -> paralleTest()).start();
new Thread(() -> paralleTest()).start();
}

  实际上,在不同的机器上执行,这段代码花费的时间都不一样。

  既然是并行,那肯定得有个并行度。太低了,体现不到并行的能能力;太大了,又浪费了上下文切换的时间。我是很沮丧的发现,很多高级研发,将线程池的各种参数背的滚瓜烂熟,各种调优,竟然敢睁一只眼闭一只眼的在I/O密集型业务中用上parallelStream

  要了解这个并行度,我们需要查看具体的构造方法。在ForkJoinPool类中找到这样的代码。

  try { // ignore exceptions in accessing/parsing properties
String pp = System.getProperty
("java.util.concurrent.ForkJoinPool.common.parallelism");
if (pp != null)
parallelism = Integer.parseInt(pp);
fac = (ForkJoinWorkerThreadFactory) newInstanceFromSystemProperty(
"java.util.concurrent.ForkJoinPool.common.threadFactory");
handler = (UncaughtExceptionHandler) newInstanceFromSystemProperty(
"java.util.concurrent.ForkJoinPool.common.exceptionHandler");
} catch (Exception ignore) {
}

  if (fac == null) {
if (System.getSecurityManager() == null)
fac = defaultForkJoinWorkerThreadFactory;
else // use security-managed default
fac = new InnocuousForkJoinWorkerThreadFactory();
}
if (parallelism < 0 && // default 1 less than #cores
(parallelism = Runtime.getRuntime().availableProcessors() - 1) <= 0)
parallelism = 1;
if (parallelism > MAX_CAP)
parallelism = MAX_CAP;

  可以看到,并行度到底是多少,是由下面的参数来控制的。如果无法获取这个参数,则默认使用CPU个数-1的并行度。

  可以看到,这个函数是为了计算密集型业务去设计的。如果你喂给它一大堆任务,它就会由并行执行退变成类似于串行的效果。

  -Djava.util.concurrent.ForkJoinPool.common.parallelism=N

  即使你使用-Djava.util.concurrent.ForkJoinPool.common.parallelism=N设置了一个初始值大小,它依然有问题。

  因为,parallelism这个变量是final的,一旦设定,不允许修改。也就是说,上面的参数只会生效一次。

  张三可能使用下面的代码,设置了并行度大小为20

  System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "20");

  李四可能用同样的方式,设置了这个值为30。那实际在项目中用的是哪个值,那就得问JVM是怎么加载的类信息了。

  这种方式并不太非常靠谱。

  一种解决方式

  我们可以通过提供外置的forkjoinpool,也就是改变提交方式,来实现不同类型的任务分离。

  代码如下所示,通过显示的代码提交,即可实现任务分离。

  ForkJoinPool pool = new ForkJoinPool(30);

  final long begin = System.currentTimeMillis();
try {
pool.submit(() ->
numbers.parallelStream().map(k -> {
try {
Thread.sleep(1000);
System.out.println((System.currentTimeMillis() - begin) + "ms => " + k + " \t" + Thread.currentThread());
} catch (InterruptedException e) {
e.printStackTrace();
}
return k;
}).collect(Collectors.toList())).get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}

  这样,不同的场景,就可以拥有不同的并行度。这种方式和CountDownLatch有异曲同工之妙,我们需要手动管理资源。

  使用了这种方式,代码量增加,已经和优雅关系不大了,不仅不优雅,而且丑得要命。白天鹅变成了丑小鸭,你还会爱它么?

作者简介:小姐姐味道 (xjjdog),一个不允许程序员走弯路的公众号。聚焦基础架构和Linux。十年架构,日百亿流量,与你探讨高并发世界,给你不一样的味道。我的个人微信xjjdog0,欢迎添加好友,进一步交流。

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
新婚两月遭家暴瘫痪失明,婆家转移全部财产,母亲:11年判的太轻

新婚两月遭家暴瘫痪失明,婆家转移全部财产,母亲:11年判的太轻

易玄
2026-06-26 20:12:30
韩红麻烦大了!不到24小时再迎噩耗,其戒指、腕表价格不菲疑炫富

韩红麻烦大了!不到24小时再迎噩耗,其戒指、腕表价格不菲疑炫富

乡野小珥
2026-06-27 04:52:34
离谱!3亿身家、14任鲜肉、5万人报名、一天28次,泰国富婆太荒诞

离谱!3亿身家、14任鲜肉、5万人报名、一天28次,泰国富婆太荒诞

阿讯说天下
2026-06-26 12:08:56
斯卡洛尼:没有更想碰的对手,更希望世界杯明天就结束,我们是冠军

斯卡洛尼:没有更想碰的对手,更希望世界杯明天就结束,我们是冠军

懂球帝
2026-06-27 15:45:09
北京发布雷电黄警!今夜要下雨,预计持续时间——

北京发布雷电黄警!今夜要下雨,预计持续时间——

BRTV新闻
2026-06-27 16:20:03
最后的疯狂:许家印被抓捕的失控三秒钟,简直是惊心动魄

最后的疯狂:许家印被抓捕的失控三秒钟,简直是惊心动魄

橘仔看世界
2026-06-27 08:38:00
A股重磅资金报告:周五砸盘元凶浮出水面!难怪A股总是涨不起来!

A股重磅资金报告:周五砸盘元凶浮出水面!难怪A股总是涨不起来!

丁丁鲤史纪
2026-06-27 11:41:29
凌晨5点起,小组赛最后6场:C罗J罗争头名,梅西冲前无古人纪录

凌晨5点起,小组赛最后6场:C罗J罗争头名,梅西冲前无古人纪录

全景体育V
2026-06-27 15:27:04
打过北京科兴的人注意!长期影响有定论,别再被小道消息吓住

打过北京科兴的人注意!长期影响有定论,别再被小道消息吓住

王二哥老搞笑
2026-06-27 14:27:39
2026年6月27日,全国各大银行最新存款利率

2026年6月27日,全国各大银行最新存款利率

星辰宇的不羁
2026-06-27 13:43:41
白玉兰奖红毯生图来了!杨幂脸上凸起一条线,杨紫用力过猛妆太浓

白玉兰奖红毯生图来了!杨幂脸上凸起一条线,杨紫用力过猛妆太浓

萌神木木
2026-06-26 19:59:56
我被调到水库无人问津,三年后,贬我的女书记以领导身份来视察

我被调到水库无人问津,三年后,贬我的女书记以领导身份来视察

千秋文化
2026-06-24 19:37:39
随着比利时5-1,伊朗1-1,世界杯最新积分榜出炉

随着比利时5-1,伊朗1-1,世界杯最新积分榜出炉

侧身凌空斩
2026-06-27 13:07:54
中央定调,2026年基本养老金调整在即,企业退休涨幅2.6%难不难?

中央定调,2026年基本养老金调整在即,企业退休涨幅2.6%难不难?

虎哥闲聊
2026-06-26 17:27:29
摩根士丹利:光通信退潮,网络设备正成为新主线

摩根士丹利:光通信退潮,网络设备正成为新主线

新浪财经
2026-06-26 17:43:36
曼联铁腰世界杯重伤被抬下,疑似ACL撕裂洒泪!夏窗转会恐成泡影

曼联铁腰世界杯重伤被抬下,疑似ACL撕裂洒泪!夏窗转会恐成泡影

罗米的曼联博客
2026-06-27 11:34:53
四提白玉兰终封后,杨紫发文:仍觉不真实

四提白玉兰终封后,杨紫发文:仍觉不真实

小椰的奶奶
2026-06-27 13:41:47
张钧甯回应原名上热搜 为原名难认向大家道歉

张钧甯回应原名上热搜 为原名难认向大家道歉

东方不败然多多
2026-06-26 16:47:17
200亿爆雷案终审落槌:前广州首富张劲终审被判无期

200亿爆雷案终审落槌:前广州首富张劲终审被判无期

都市快报橙柿互动
2026-06-27 09:56:49
三角恋实锤!姆巴佩约会西班牙超模,维尼修斯曾疯狂点赞?

三角恋实锤!姆巴佩约会西班牙超模,维尼修斯曾疯狂点赞?

绿茵八卦君
2026-06-27 11:00:03
2026-06-27 17:27:00
小姐姐味道
小姐姐味道
十年架构,日百亿流量
329文章数 1203关注度
往期回顾 全部

科技要闻

GPT-5.6发布,你暂时用不了!Mythos也放行

头条要闻

佛得角队历史性闯入世界杯32强 主帅回应

头条要闻

佛得角队历史性闯入世界杯32强 主帅回应

体育要闻

韩国球迷感谢西班牙:他们本可做掉我们

娱乐要闻

四提白玉兰终封后,杨紫:仍觉不真实

财经要闻

OpenAI推迟IPO重创软银!

汽车要闻

首搭华为乾崑智驾ADS5 启境GT7上市售价20.99万-32.99万元

态度原创

亲子
房产
数码
教育
手机

亲子要闻

果然还是哥哥比较厉害

房产要闻

全国高考大放水,300分就能上本科!论上岸率,海南没输过!

数码要闻

优派TD2465-CN触控显示器开售:23.8英寸1080P VA面板,2699元

教育要闻

高一学霸一个月备战高考,斩获620分,已提前入围中科大少年班,独家揭秘备战过程

手机要闻

业内无敌手!荣耀直板机要上12000mAh巨量电池

无障碍浏览 进入关怀版