前言
在提到多线程的时候我们大都会想到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框架
常见集合线性是否安全可参考下图:
参考文章: