日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

system流怎么判断为空_并行流ParallelStream中隐藏的陷阱

發布時間:2024/7/23 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 system流怎么判断为空_并行流ParallelStream中隐藏的陷阱 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

點擊上方藍字 ↑↑ Throwable文摘

關注公眾號設置星標,不定時推送高質量原創文章

關注

前提

這篇文章介紹一下日常開發中并行流ParallelStream中隱藏的陷阱,這個問題其實離我們很近,特別是喜歡使用JDK1.8+的流式編程的伙伴,應該會深有感觸。

一個故意而為的例子

下面舉一個故意而為的例子,實際上應該不會有類似的業務代碼:

public?class?ParallelStreamMain?{

????public?static?void?main(String[]?args)?throws?Exception?{
????????List>?array?=?new?ArrayList<>();
????????List?item1?=?new?ArrayList<>();
????????List?item2?=?new?ArrayList<>();
????????List?target?=?new?ArrayList<>(100);
????????array.add(item1);
????????array.add(item2);
????????array.parallelStream().forEach(x?->?{for?(int?i?=?0;?i?100000;?i++)?{
????????????????target.add(i);
????????????}
????????});
????????System.out.println(target.size());
????}
}

某一次執行結果為:163913。如果不停地執行這個main方法,最終都會得到一個非200000的結果,這里的問題就在于使用了并行流parallelStream()方法。ParallelStream底層使用了Fork/Join框架實現,也就是應用了線程池ForkJoinPool把并行流中的節點抽象為ForkJoinTask進行計算,背后用到的"任務竊取"等原理這里就不進行展開,只需要明確:

  • ForkJoinPool一般使用Runtime.getRuntime().availableProcessors()(此值一般認為是物理機器的邏輯核心數量)作為并行度(parallelism),簡單認為是可并發執行的任務數,并不是工作線程數。
  • 多核機器中,使用ParallelStream在流的節點中的所有操作都相當于在「一個多線程環境中」進行操作,里面的所有操作都會產生不可預期的結果,例如可能會數組越界、添加元素丟失、部分下標index的引用為NULL等等。

一個仿真例子

寫這篇文章不是有意為之,其實很早之前筆者曾經遇到一個比較隱蔽的生產故障,其中有一段訪問量比較低的代碼大致如下:

@Data
private?static?class?OrderDTO?{

????private?String?orderId;
????private?OrderStatus?orderStatus;
????private?BigDecimal?amount;
????private?Long?customerId;
}

@Data
private?static?class?Order?{

????private?Long?id;
????private?String?orderId;
????private?Integer?orderStatus;
????private?BigDecimal?amount;
????private?Long?customerId;
????private?OffsetDateTime?createTime;
????private?OffsetDateTime?editTime;
}

public?void?groupByOrderStatus(Long?customerId)?{
????List?orders?=?orderDao.selectByCustomerId(customerId);
????List?orderDTOList?=?new?ArrayList<>();
????orders.parallelStream().forEach(order?->?{
????????OrderDTO?dto?=?new?OrderDTO();
????????......
????????orderDTOList.add(dto);
????});
????Map>?collect?
????????????=?orderDTOList.stream().collect(Collectors.groupingBy(item?->?item.getOrderStatus().getCode()));
????......
}

該方法的功能是通過客戶ID查詢訂單列表,然后把訂單列表轉化為OrderDTO列表,然后再按照訂單狀態字段進行分組。通過生產日志和測試回歸發現,上面的代碼段中groupByOrderStatus()方法會偶發空指針異常。

初次出現問題的時候,由于開發者通過Lambda表達式把多處代碼壓縮為1行,所以從異常棧比較難排查具體發生問題的代碼,后面把Lambda表達式以句點起點拆分為多行上線后觀察一段時間,最終定位到發生空指針異常的代碼段為Collectors.groupingBy(item -> item.getOrderStatus().getCode()),也就是OrderDTO實例中的orderStatus為空對象。這里顯然,groupByOrderStatus()方法其實是被封閉在線程棧中調用,本不應該有多個線程去并發修改其中的內容,這里只剩下一個疑點:使用了parallelStream()。后來直接把parallelStream()修改為stream()重新上線,該空指針問題不再復現。

Lambda/Stream其實并不是天然線程安全的,線程安全的前提是它們本身被線程封閉調用,并且不引入多線程環境,像使用了并行流,本質就是引入了多線程環境。所以,在開發功能的時候,需要仔細思考一下:

  • 是否真的有必要使用Lambda和流式編程?
  • 是否真的有必要用到并行流?如果使用了并行流,是否需要考慮引入額外的同步機制,例如鎖?
  • 其實并發并不能提高性能,只能提高吞吐量,應該著重去發現和優化性能瓶頸,而不是拼命地把上游改造成并發調用。
  • ?

    筆者有代碼潔癖,當時還發現了上面的代碼存在映射操作,正確來說應該使用map()函數,而不是forEach()去遍歷元素重新裝進去另一個列表,方法中的邏輯體現了原開發者其實對Lambda一知半解。

    ?

    小結

    回到最初那個問題,其實使用并行流也可以保證執行結果和預期一致,不過一定需要引入額外的同步機制,例如這里使用「監視器」進行同步:

    public?class?ParallelStreamMain?{

    ????public?static?void?main(String[]?args)?throws?Exception?{
    ????????List>?array?=?new?ArrayList<>();
    ????????List?item1?=?new?ArrayList<>();
    ????????List?item2?=?new?ArrayList<>();
    ????????List?target?=?new?ArrayList<>(100);
    ????????array.add(item1);
    ????????array.add(item2);final?Object?monitor?=?new?Object();
    ????????array.parallelStream().forEach(x?->?{synchronized?(monitor)?{for?(int?i?=?0;?i?100000;?i++)?{
    ????????????????????target.add(i);
    ????????????????}
    ????????????}
    ????????});
    ????????System.out.println(target.size());
    ????}
    }

    上面的方法無論執行多少次,最終都只會輸出:200000。

    (本文完 c-1-d e-a-20200710)

    總結

    以上是生活随笔為你收集整理的system流怎么判断为空_并行流ParallelStream中隐藏的陷阱的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 男人的天堂一级片 | 天天操天天射天天舔 | 最新中文字幕免费视频 | 无码毛片aaa在线 | 性欧美丰满熟妇xxxx性久久久 | 老司机深夜影院 | 日韩偷拍一区 | 在线中出 | 久久精品视频免费 | 欧美日本在线看 | 精品久久久噜噜噜久久久 | 亚洲最大av| 操极品少妇| 久久国产一 | 黄色永久免费网站 | 三级黄网 | 中文字幕免费观看 | 国产一区二区视频在线免费观看 | 99只有精品| 老牛影视av老牛影视av | 亚洲六月丁香色婷婷综合久久 | 成人免费无遮挡无码黄漫视频 | 精品国产伦一区 | 午夜在线视频播放 | 视频在线观看免费 | 青青在线 | 偷拍青青草 | 丁香六月在线 | 好吊色网站 | 激情六月天 | 国产成人av片 | 成人免费黄色 | 国产精品国产 | 日日夜夜添 | 日本www黄 | 自拍偷拍国产 | 91精品视频一区 | www在线免费观看 | 免费黄色短片 | 亚洲蜜桃av一区二区 | 91色区| 日本欧美久久久久免费播放网 | 久久久久无码精品 | 日韩av在线看免费观看 | 成人免费黄色大片v266 | 黄色网页在线免费观看 | 免费网站91 | 爱插网 | 国产丰满美女做爰 | 黄色福利 | 亚洲欧洲精品一区二区 | 奇米影视网 | 亚洲作爱| 国产成人精品久久二区二区91 | www射| 神马午夜av | 97视频一区 | 欧美老女人性视频 | 久青草视频在线观看 | 欧美成人一区二区三区片免费 | 欧美伦理一区二区三区 | 黄色网在线免费观看 | 精品一区二区三区无码按摩 | 无码国产伦一区二区三区视频 | 久操视频在线观看免费 | 天堂激情网 | 欧美日韩视频一区二区三区 | 国产视频在 | 超碰午夜 | 日本高清视频免费观看 | 国产亚洲片 | 在线成人看片 | 久久成人福利视频 | 国产一级高清 | 在线亚洲精品 | 九九精品网| 亚洲插插| 精品人妻无码专区视频 | 影音先锋中文字幕一区 | 日韩欧美中文字幕一区二区三区 | 日韩精品成人免费观看视频 | 羞羞动漫免费观看 | 校园伸入裙底揉捏1v1h | 巨茎人妖videos另类 | 琪琪色在线观看 | 国产在线拍揄自揄拍无码视频 | 中文天堂在线观看 | 图片区视频区小说区 | 国产精品一品二区三区的使用体验 | 日韩在线网 | 欧美日韩激情在线一区二区三区 | 中文字幕av网站 | 欧美整片在线观看 | 国产123| 黄色成年人 | 91免费视频网址 | 欧美男人亚洲天堂 | 亚洲欧洲综合 | 午夜看黄神器 |