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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

java8使用parallelStream并行流造成数据丢失或下标越界异常解决方案

發布時間:2023/12/19 综合教程 32 生活家
生活随笔 收集整理的這篇文章主要介紹了 java8使用parallelStream并行流造成数据丢失或下标越界异常解决方案 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

描述

我們先看一段使用了并行流的代碼

    @Test
    public void testStream() {
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < 10000; i++) {
            list.add(i);
        }
        System.out.println(list.size());
        List<Integer> streamList = new ArrayList<>();
        list.parallelStream().forEach(streamList::add);
        System.out.println(streamList.size());
    }

編譯結果:

觀察發現,原來集合中的數據有10000條,但是使用并行流遍歷數據插入到新集合streamList中后,新的集合中只有5746條數據。并且會在多次之后可能會出現數組下標越界異常,顯然這里的代碼是不合邏輯的。

分析

parallelStream中使用的是ForkJobTask。Fork/Join的框架是通過把一個大任務不斷fork成許多子任務,然后多線程執行這些子任務,最后再Join這些子任務得到最終結果。關于分支/合并框架的使用案例可以看我的這篇文章(用分支/合并框架執行并行求和)。從程序上看,就是先將list集合fork成多段,然后多線程添加到streamList的結合中,而streamList是ArrayList類型,它的add方法并不能保證原子性。

ArrayList的add方法源碼如下:

    /**
     * Appends the specified element to the end of this list.
     *
     * @param e element to be appended to this list
     * @return <tt>true</tt> (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

可以看到add方法可以概括為以下兩個步驟

ensureCapacityInternal(),確認下當前ArrayList中的數組,是否還可以加入新的元素。如果不行,就會再申請一個:int newCapacity = oldCapacity + (oldCapacity >> 1) 大小的數組(這個容量相當于:1 + 1/2 = 1.5倍),然后將數據copy過去。
elementData[size++] = e:添加元素到elementData數組中。

在并發情況下,如果同時有A、B兩個線程同時執行add,在第一步ensureCapacityInternal校驗數組容量時,A、B線程都發現當前容量還可以添加最有一個元素,不需擴容;因此進入第二步,此時,A線程先執行完,數組容量已滿,然后B線程再對elementData賦值時,就會拋出“ArrayIndexOutOfBoundsException”。

解決方案

第一種:將parallelStream改成stream,或者直接使用foreach處理。這可以通過判斷并發處理真實能帶來多大的好處,做取舍。

第二種:使用resultList =new CopyOnWriteArrayList<>();這是個線程安全的類。從源碼上看,CopyOnWriteArrayList在add操作時,通過ReentrantLock進行加鎖,防止并發寫。不給過CopyOnWriteArrayList,每次add操作都是把原數組中的元素拷貝一份到新數組中,然后在新數組中添加新元素,最后再把引用指向新數組。這會導致頻繁的對象創建,況且數組還是需要一塊連續的內存空間,如果有大量add操作,慎用。

第三種:使用包裝類resultList = Collections.synchronizedList(Arrays.asList());

總結

在從stream和parallelStream方法中進行選擇時,我們可以考慮以下幾個問題:

1.是否需要并行?

2.任務之間是否是獨立的?是否會引起任何競態條件?

3.結果是否取決于任務的調用順序?

對于問題1,在回答這個問題之前,你需要弄清楚你要解決的問題是什么,數據量有多大,計算的特點是什么?并不是所有的問題都適合使用并發程序來求解,比如當數據量不大時,順序執行往往比并行執行更快。畢竟,準備線程池和其它相關資源也是需要時間的。但是,當任務涉及到I/O操作并且任務之間不互相依賴時,那么并行化就是一個不錯的選擇。通常而言,將這類程序并行化之后,執行速度會提升好幾個等級。

對于問題2,如果任務之間是獨立的,并且代碼中不涉及到對同一個對象的某個狀態或者某個變量的更新操作,那么就表明代碼是可以被并行化的。

對于問題3,由于在并行環境中任務的執行順序是不確定的,因此對于依賴于順序的任務而言,并行化也許不能給出正確的結果。

總結

以上是生活随笔為你收集整理的java8使用parallelStream并行流造成数据丢失或下标越界异常解决方案的全部內容,希望文章能夠幫你解決所遇到的問題。

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

主站蜘蛛池模板: 成人在线观看国产 | 日本55丰满熟妇厨房伦 | 欧美午夜视频 | 免费三级大片 | 精品少妇白浆小泬60P | 91色国产 | 在线观看你懂的网址 | 他揉捏她两乳不停呻吟动态图 | 玖玖精品在线视频 | jlzzzjlzzz国产免费观看 | 成人免费超碰 | 五月激情五月婷婷 | 黄色综合网 | 麻豆传媒一区二区 | 国产精品婷婷午夜在线观看 | 国产精品第二页 | 精品国产专区 | 天天干夜夜欢 | 西川结衣在线观看 | 综合精品在线 | 午夜在线视频免费观看 | julia一区 | 极品美女一区二区三区 | 国产乱在线| 国产亚洲欧美精品久久久久久 | 深夜福利国产精品 | 国产精品久久久久久久久绿色 | 成人精品二区 | 日本少妇喷水 | 红桃视频亚洲 | 女人天堂av | 国产山村乱淫老妇女视频 | 日韩av三级在线 | 亚洲天堂网一区二区 | 欧美20p| 久久韩国| 欧洲mv日韩mv国产 | 日韩一级伦理片 | 都市激情亚洲一区 | 日本激情网址 | 91精品久久人妻一区二区夜夜夜 | 欧美成人一区二免费视频软件 | 欧美黄色a视频 | 9.1成人看片免费版 日韩经典在线 | 国产美女作爱全过程免费视频 | 在线观看日韩 | 国产成人无码一区二区三区在线 | 欧美午夜精品久久久久久人妖 | 受虐m奴xxx在线观看 | 欧美精品久久久久久久久 | 久久久久久久久久久综合 | 成人区一区二区 | 成人高潮片免费 | 国产乱淫av片杨贵妃 | 精品香蕉99久久久久网站 | 午夜aaa片一区二区专区 | 深爱五月激情网 | 91成人看片 | 在线免费小电影 | 自拍偷拍第八页 | 欧美精品小视频 | 久久久99精品免费观看 | a在线观看| 高清日韩一区二区 | 欧美一区二区三区成人 | 免费一级毛片麻豆精品 | 成人免费毛片果冻 | 日日夜夜免费精品 | 亚洲成人一 | 少妇一级淫片免费 | 黄色小说在线观看视频 | aaa黄色| 四虎成人影视 | www,xxx69 japan| 免费观看日本 | 亚洲丁香色 | 亚洲v欧美v | 国产精品亚洲二区 | 欧美性极品xxxx做受 | 国产性生活一级片 | 精品福利影院 | 久久综合九九 | 国产精品啪 | av在线大全| 黄色小视频在线免费看 | 日韩在线视频播放 | 日本成人在线免费 | 欧美视频久久久 | 永久黄网站 | 男人天堂社区 | 欧美特一级 | 少妇一级淫片免费放2 | 无码国产精品久久一区免费 | 在线观看黄网址 | 国产人妻久久精品一区二区三区 | 理论片琪琪午夜电影 | 亚洲色图偷 | 亚洲国产精品成人 | 国产18页|