java基础理论学习笔记(3)——ArrayList等集合类不安全问题?解决方案:vector、Collections.sync工具类,或者JUC的CopyOnWriteArrList

ArrayList不是线程安全类,在多线程同时写的情况下,会抛出java.util.ConcurrentModificationException异常。如下代码,开启30个线程同时对ArrayList进行写操作,会报并发异常错。

private static void listNotSafe() {
    List list=new ArrayList<>();
    for (int i = 1; i <= 30; i++) {
        new Thread(() -> {
            list.add(UUID.randomUUID().toString().substring(0, 8));
            System.out.println(Thread.currentThread().getName() + "\t" + list);
        }, String.valueOf(i)).start();
    }
}

解决方法

  1. 使用VectorArrayList所有方法加synchronized,太重)。
  2. 使用Collections.synchronizedList()转换成线程安全类。
  3. 使用java.concurrent.CopyOnWriteArrayList(推荐)

第一个方案中,vector源码中可以看到,用上了synchronize修饰

而且他是在1.0就出来了;而ArrayList是1.2出来的,由于vector性能太差,后者是为了解决这个问题而搞出来的,把并发问题交给其他方案去处理是更妥当的。

第二个方案中,可在jdk API中看到:

java基础理论学习笔记(3)——ArrayList等集合类不安全问题?解决方案:vector、Collections.sync工具类,或者JUC的CopyOnWriteArrList_第1张图片

其中hashset的底层是hashmap实现的,他的value存储的都是固定值。

java基础理论学习笔记(3)——ArrayList等集合类不安全问题?解决方案:vector、Collections.sync工具类,或者JUC的CopyOnWriteArrList_第2张图片

HashSet底层是用HashMap实现的。既然是用HashMap实现的,那HashMap.put()需要传两个参数,而HashSet.add()传一个参数,这是为什么?实际上HashSet.add()就是调用的HashMap.put(),只不过Value被写死了,是一个private static final Object对象。

HashMap不是线程安全的,Hashtable是线程安全的,但是跟Vector类似,太重量级。所以也有类似CopyOnWriteMap,只不过叫ConcurrentHashMap

第三个方案中原理:

java基础理论学习笔记(3)——ArrayList等集合类不安全问题?解决方案:vector、Collections.sync工具类,或者JUC的CopyOnWriteArrList_第3张图片

java基础理论学习笔记(3)——ArrayList等集合类不安全问题?解决方案:vector、Collections.sync工具类,或者JUC的CopyOnWriteArrList_第4张图片

写的时候必须对对象加锁。

写是在自己空间操作的,不影响并发读,所以这是读写分离的。

List list = new CopyOnWriteArrayList<>();

你可能感兴趣的:(java基础)