前言
在提到多線程的時候我們大都會想到ArrayList 與 HashMap,這兩個類型都是非線性安全的!在多個線程同時操作改集合對象時,會出現哪些問題呢?在傳統的集合包內的集合類到底為什么線程非安全呢?在新的JUC包類又有什么可以替代呢?
介紹
①為什么ArrayList 是線性不安全的?
②替代措施及解決方案?
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
②某些線程並未打印
③數組下標越界異常
由此我們可以得出,在多線程情況下操作ArrayList 並不是線性安全的。那如何解決呢?
第一種方案:
使用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框架
常見集合線性是否安全可參考下圖:
參考文章: