欧美一级特黄大片做受成人-亚洲成人一区二区电影-激情熟女一区二区三区-日韩专区欧美专区国产专区

Java8中parallelStream并發(fā)安全的示例分析

這篇文章主要介紹Java8中parallelStream并發(fā)安全的示例分析,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!

十多年的伊通網(wǎng)站建設(shè)經(jīng)驗(yàn),針對(duì)設(shè)計(jì)、前端、開發(fā)、售后、文案、推廣等六對(duì)一服務(wù),響應(yīng)快,48小時(shí)及時(shí)工作處理。成都全網(wǎng)營(yíng)銷的優(yōu)勢(shì)是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動(dòng)調(diào)整伊通建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計(jì),從而大程度地提升瀏覽體驗(yàn)。創(chuàng)新互聯(lián)從事“伊通網(wǎng)站設(shè)計(jì)”,“伊通網(wǎng)站推廣”以來,每個(gè)客戶項(xiàng)目都認(rèn)真落實(shí)執(zhí)行。

背景

Java8的stream接口極大地減少了for循環(huán)寫法的復(fù)雜性,stream提供了map/reduce/collect等一系列聚合接口,還支持并發(fā)操作:parallelStream。

在爬蟲開發(fā)過程中,經(jīng)常會(huì)遇到遍歷一個(gè)很大的集合做重復(fù)的操作,這時(shí)候如果使用串行執(zhí)行會(huì)相當(dāng)耗時(shí),因此一般會(huì)采用多線程來提速。Java8的paralleStream用fork/join框架提供了并發(fā)執(zhí)行能力。但是如果使用不當(dāng),很容易陷入誤區(qū)。

Java8的paralleStream是線程安全的嗎

一個(gè)簡(jiǎn)單的例子,在下面的代碼中采用stream的forEach接口對(duì)1-10000進(jìn)行遍歷,分別插入到3個(gè)ArrayList中。其中對(duì)第一個(gè)list的插入采用串行遍歷,第二個(gè)使用paralleStream,第三個(gè)使用paralleStream的同時(shí)用ReentryLock對(duì)插入列表操作進(jìn)行同步:

private static List<Integer> list1 = new ArrayList<>();
private static List<Integer> list2 = new ArrayList<>();
private static List<Integer> list3 = new ArrayList<>();
private static Lock lock = new ReentrantLock();

public static void main(String[] args) {
 IntStream.range(010000).forEach(list1::add);

 IntStream.range(010000).parallel().forEach(list2::add);

 IntStream.range(010000).forEach(i -> {
 lock.lock();
 try {
  list3.add(i);
 }finally {
  lock.unlock();
 }
 });

 System.out.println("串行執(zhí)行的大?。?quot; + list1.size());
 System.out.println("并行執(zhí)行的大?。?quot; + list2.size());
 System.out.println("加鎖并行執(zhí)行的大小:" + list3.size());
}

執(zhí)行結(jié)果:

串行執(zhí)行的大?。?0000
并行執(zhí)行的大小:9595
加鎖并行執(zhí)行的大?。?0000

并且每次的結(jié)果中并行執(zhí)行的大小不一致,而串行和加鎖后的結(jié)果一直都是正確結(jié)果。顯而易見,stream.parallel.forEach()中執(zhí)行的操作并非線程安全。

那么既然paralleStream不是線程安全的,是不是在其中的進(jìn)行的非原子操作都要加鎖呢?我在stackOverflow上找到了答案:

  • https://codereview.stackexchange.com/questions/60401/using-java-8-parallel-streams

  • https://stackoverflow.com/questions/22350288/parallel-streams-collectors-and-thread-safety

在上面兩個(gè)問題的解答中,證實(shí)paralleStream的forEach接口確實(shí)不能保證同步,同時(shí)也提出了解決方案:使用collect和reduce接口。

  • http://docs.oracle.com/javase/tutorial/collections/streams/parallelism.html

在Javadoc中也對(duì)stream的并發(fā)操作進(jìn)行了相關(guān)介紹:

The Collections Framework provides synchronization wrappers, which add automatic synchronization to an arbitrary collection, making it thread-safe.

Collections框架提供了同步的包裝,使得其中的操作線程安全。

所以下一步,來看看collect接口如何使用。

stream的collect接口

閑話不多說直接上源碼吧,Stream.java中的collect方法句柄:

<R, A> R collect(Collector<? super T, A, R> collector);

在該實(shí)現(xiàn)方法中,參數(shù)是一個(gè)Collector對(duì)象,可以使用Collectors類的靜態(tài)方法構(gòu)造Collector對(duì)象,比如Collectors.toList(),toSet(),toMap(),etc,這塊很容易查到API故不細(xì)說了。

除此之外,我們?nèi)绻赾ollect接口中做更多的事,就需要自定義實(shí)現(xiàn)Collector接口,需要實(shí)現(xiàn)以下方法:

Supplier<A> supplier();
BiConsumer<A, T> accumulator();
BinaryOperator<A> combiner();
Function<A, R> finisher();
Set<Characteristics> characteristics();

要輕松理解這三個(gè)參數(shù),要先知道fork/join是怎么運(yùn)轉(zhuǎn)的,一圖以蔽之:

Java8中parallelStream并發(fā)安全的示例分析

上圖來自:http://www.infoq.com/cn/articles/fork-join-introduction

簡(jiǎn)單地說就是大任務(wù)拆分成小任務(wù),分別用不同線程去完成,然后把結(jié)果合并后返回。所以第一步是拆分,第二步是分開運(yùn)算,第三步是合并。這三個(gè)步驟分別對(duì)應(yīng)的就是Collector的supplier,accumulator和combiner。talk is cheap show me the code,下面用一個(gè)例子來說明:

輸入是一個(gè)10個(gè)整型數(shù)字的ArrayList,通過計(jì)算轉(zhuǎn)換成double類型的Set,首先定義一個(gè)計(jì)算組件:

Compute.java:

public class Compute {
public Double compute(int num) {
 return (double) (2 * num);
}
}

接下來在Main.java中定義輸入的類型為ArrayList的nums和類型為Set的輸出結(jié)果result:

private List<Integer> nums = new ArrayList<>();
private Set<Double> result = new HashSet<>();

定義轉(zhuǎn)換list的run方法,實(shí)現(xiàn)Collector接口,調(diào)用內(nèi)部類Container中的方法,其中characteristics()方法返回空set即可:

public void run() {
 // 填充原始數(shù)據(jù),nums中填充0-9 10個(gè)數(shù)
 IntStream.range(010).forEach(nums::add);
 //實(shí)現(xiàn)Collector接口
 result = nums.stream().parallel().collect(new Collector<IntegerContainerSet<Double>>() {

 @Override
 public Supplier<Containersupplier() {
  return Container::new;
 }

 @Override
 public BiConsumer<ContainerIntegeraccumulator() {
  return Container::accumulate;
 }

 @Override
 public BinaryOperator<Containercombiner() {
  return Container::combine;
 }

 @Override
 public Function<ContainerSet<Double>> finisher() {
  return Container::getResult;
 }

 @Override
 public Set<Characteristicscharacteristics() {
  // 固定寫法
  return Collections.emptySet();
 }
 });
}

構(gòu)造內(nèi)部類Container,該類的作用是一個(gè)存放輸入的容器,定義了三個(gè)方法:

  • accumulate方法對(duì)輸入數(shù)據(jù)進(jìn)行處理并存入本地的結(jié)果

  • combine方法將其他容器的結(jié)果合并到本地的結(jié)果中

  • getResult方法返回本地的結(jié)果

Container.java:

class Container {
 // 定義本地的result
 public Set<Doubleset;

 public Container() {
 this.set = new HashSet<>();
 }

 public Container accumulate(int num) {
 this.set.add(compute.compute(num));
 return this;
 }

 public Container combine(Container container) {
 this.set.addAll(container.set);
 return this;
 }

 public Set<Double> getResult() {
 return this.set;
 }
}

在Main.java中編寫測(cè)試方法:

public static void main(String[] args) {
 Main main = new Main();
 main.run();
 System.out.println("原始數(shù)據(jù):");
 main.nums.forEach(i -> System.out.print(i + " "));
 System.out.println("\n\ncollect方法加工后的數(shù)據(jù):");
 main.result.forEach(i -> System.out.print(i + " "));
}

輸出:

原始數(shù)據(jù):
0 1 2 3 4 5 6 7 8 9

collect方法加工后的數(shù)據(jù):
0.0 2.0 4.0 8.0 16.0 18.0 10.0 6.0 12.0 14.0

我們將10個(gè)整型數(shù)值的list轉(zhuǎn)成了10個(gè)double類型的set,至此驗(yàn)證成功~

以上是“Java8中parallelStream并發(fā)安全的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!

名稱欄目:Java8中parallelStream并發(fā)安全的示例分析
當(dāng)前鏈接:http://aaarwkj.com/article4/gjgeoe.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供靜態(tài)網(wǎng)站、網(wǎng)站改版、做網(wǎng)站、面包屑導(dǎo)航云服務(wù)器、外貿(mào)建站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

營(yíng)銷型網(wǎng)站建設(shè)
欧美午夜一区二区电影| 久久 久久国内精品亚洲| 国产强烈高潮粗暴对白| 91亚洲国产成人精品性色| 最新手机免费黄色av网站| 欧美一级免费黄片在线播放| 日本不卡一区二区在线视频| 在线午夜免费视频观看| 黄色高清无遮挡在线观看| 森泽佳奈在线视频观看| 国产欧美精品久久三级| 一区二区三区欧美黑人| 午夜激情毛片在线观看| 国产白浆视频在线观看| 国产亚洲综合久久系列| 黄色欧美在线观看免费| 最美是你免费视频观看| 亚洲国产免费一区二区| 成人黄色av网站在线观看| 亚洲国产综合六月深深爱| 一区二区三区av天堂| 国产看片色网站亚洲av| a一级成人插少妇的逼| av全欧国男人在线天堂| 午夜福利尤物一区二区| 曰本真人性做爰视频免费| 久久精品国产亚洲av高清不卡| 日本国产美女精品一区二区| 国产午夜在线影院一区二区| av熟女乱一区二区三区| 国产精品免费视频一区二区三区| 精品在线免费视频观看| 一区二区在线观看激情| 亚洲国产一区二区高清| 青青草网站在线观看视频| 91成人精品永久在线观看| 欧美一区二区三区情色| 色婷婷久久五月中文字幕| 韩国黄色三级一区二区| 人妻一区二区三区免看| 亚洲成av在线免费不卡|