Java併發編程之支持併發的list集合

Java併發編程之-list集合的併發.java

咱們都知道Java集合類中的arrayList是線程不安全的。那麼怎麼證實是線程不安全的呢?怎麼解決在併發環境下使用安全的list集合類呢?編程

本篇是《凱哥(凱哥Java:kagejava)併發編程學習》系列之《併發集合系列》教程的第一篇:安全

本文主要內容:怎麼證實arrayList不是線程安全的?怎麼解決這個問題?以及遇到問題解決的四個步驟及從源碼來分析做者思路。多線程

一:怎麼證實arrayList在併發狀況下是線程不安全的呢?

建立一個list,用多個線程向list中添加數據。來看看結果併發

watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

查看運行結果:ide

watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

咱們發現了一個異常:java.util.ConcurrentModificationException工具

java.util.ConcurrentModificationException是什麼性能

這個異常什麼意思呢?咱們來看看這個異常源碼中類的註釋信息:學習

watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

This exception may be thrown by methods that have detected concurrent(此異常可能由檢測到併發的方法引起).優化

通常能夠理解爲,這是併發致使的異常。那麼在併發狀況下出現了異常。是否是從側面說明arrayList是不安全的呢?

二:怎麼解決這個問題

這裏凱哥順便說下,解決問題的通常步驟。

1:怎麼操做致使的故障及現象是什麼?

操做:多個線程對list進行add添加操做的時候

結果:拋出了java.util.ConcurrentModificationException異常信息

2:分析產生這個問題的緣由

舉個現實生活中的例子。簽到表,這個你們都見過吧,應該都簽到過吧。好比如今有個會議不少人來參與,須要簽到。如今,司小司正在簽到表上寫本身的名字時候,小明非要看簽到表上面有沒有本身名字。由於司小司正在簽到進行中,小明硬是要查看,把簽到表搶過去,結果就是簽到表被撕壞了或者是司小司的筆在簽到表上留下了長長的痕跡。若是上面這個例子用計算機角度分析的話。

兩個線程(司小司和小明)對一個共享變量(簽到表,能夠理解爲是人名的集合)進行讀寫操做(司小司簽到是寫操做,小明要查看本身是否簽到了,能夠理解爲讀操做),由於兩個線程都來競爭共享資源。後果就是簽到表被撕壞了或者是司小司的筆在簽到表上留下了長長的痕跡。異常現象。用到上面咱們多個線程對list進行操做的時候,就拋異常了多線程併發修改異常信息。

3:解決方案是什麼?

1:使用線程安全的List的子類Vectory

List list = new Vectory();

查看vectory的add方法源碼:

watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

發現,原來vector的add方法是加的併發鎖來保證線程安全的

2:使用collections工具類的sync方法

List list = Colletcions.synchronizedList(new ArrayList<>());

查看源碼:

watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

原來都是synchronized的。

咱們在來看看synchronizedList方法上面的註釋。

watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

發現,原來源碼中是把整個list對象做爲同步鎖的鎖。這樣來保證線程安全的

4:解決方案能夠優化嗎?優化的建議是什麼?

咱們知道synchronized關鍵字是同步鎖機制。強制並行轉化成串行的一種方案。這種對性能消耗比較大。有沒有更其餘能夠優化的方案嗎?

來看看使用JUC併發包下的:CopyOnWriteArrayList(寫時複製list)來解決吧。

先來看看這個類的add方法的源碼:

watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

從源碼中,咱們能夠看到複製了一個新的list集合,將新元素在新集合中操做。那麼爲何這種操做就不會出現併發異常呢?

由於這種思想,能夠理解爲讀寫分離的思想。由於get仍是使用原來list的get的方法。寫的時候,在複製一份原來的,而後再複製出來的基礎上進行修改的。那麼怎麼保證數據問題呢?咱們從源碼中能夠看到使用到了ReentrantLock(關於鎖相關的。凱哥(凱哥Java:kaigejava)將在後面詳細的講解的)鎖來控制的。

那麼如今使用CopyOnWriteArrayList來模擬下文章開頭簽到例子。

司小司再簽到的時候,先把簽到表複製一份,而後再新的複製出來的簽到表中進行簽到。小明是原來簽到表查看本身的信息的。這樣就不會出現爭強狀況了。想要學習Java開發的同窗,能夠參考成都Java培訓班提供的學習大綱;

相關文章
相關標籤/搜索