在提到多線程的時候咱們大都會想到ArrayList 與 HashMap,這兩個類型都是非線性安全的!在多個線程同時操做改集合對象時,會出現哪些問題呢?在傳統的集合包內的集合類到底爲何線程非安全呢?在新的JUC包類又有什麼能夠替代呢? html
①爲何ArrayList 是線性不安全的?java
②替代措施及解決方案?數組
ArrayList 咱們都知道底層是以數組方式實現的,實現了可變大小的數組,它容許全部元素,包括null。看下面一個例子:開啓多個線程操做List集合,向ArrayList中增長元素,同時去除元素。安全
import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Vector; public class ListTest { // ArrayList protected static ArrayList<Object> arrayList = new ArrayList<Object>(); // 解決措施①:使用Vector集合 protected static Vector<Object> arrayListSafe1 = new Vector<Object>(); // 解決措施②:咱們加上Collections.synchronizedList,它會自動將咱們的list方法進行改變,最後返回給咱們一個加鎖了List static List<Object> arrayListSafe2 = Collections.synchronizedList(new ArrayList<Object>()); public static void main(String[] args) { Thread[] threads = new Thread[500]; for (int i = 0; i < threads.length; i++) { threads[i] = new ArrayListThread(); threads[i].start(); } for (int i = 0; i < threads.length; i++) { try { threads[i].join();// 等待該線程終止 } catch (InterruptedException e) { e.printStackTrace(); } } // 輸出list中的對象元素 for (int i = 0; i < threads.length; i++) { System.out.println(arrayList.get(i)); } } } /** * 線程類,執行arrayList的add()增長方法 * * @author zyx * */ class ArrayListThread extends Thread { @Override public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } // 增長元素 ListTest.arrayList.add(Thread.currentThread().getName()); } }
運行代碼結果可知,會出現如下幾種狀況:多線程
①Null框架
②某些線程並未打印ide
③數組下標越界異常spa
由此咱們能夠得出,在多線程狀況下操做ArrayList 並非線性安全的。那如何解決呢?.net
第一種方案:線程
使用Vertor集合
protected static Vector<Object> arrayListSafe1 = new Vector<Object>();
第二種方案:
使用Collections.synchronizedList。它會自動將咱們的list方法進行改變,最後返回給咱們一個加鎖了List
protected static List<Object> arrayListSafe2 = Collections.synchronizedList(new ArrayList<Object>());
第三種方案:
使用JUC中的CopyOnWriteArrayList類進行替換。具體詳情可參考JUC框架
常見集合線性是否安全可參考下圖:
參考文章: