6. 集合不安全

1. list不安全

public class NotSafeDemo {
    public static void main(String[] args) {
        List<String> list =new ArrayList<>();
        for (int i=0;i<=30;i++){
            new Thread(()->{
                list.add(UUID.randomUUID().toString().substring(0,8));
                System.out.println(list);
            },String.valueOf(i)).start();
        }
    }
}

以上代码报错:ConcurrentModificationException
因为list是多线程不安全的。

解决方法1:可以用Vector,
List<String> list =new Vector<>();
因为Vector的add方法:

 public synchronized void addElement(E obj) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = obj;
    }

使用Vector效率变差

解决方法2:Collections.synchronizedList
List<String> list = Collections.synchronizedList(new ArrayList<>());

牺牲了数据一致性

解决方法3:CopyonWriteArrayList
List<String> list = new CopyOnWriteArrayList<>();
CopyOnWriteArrayList<>的源码如下:

public boolean add(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            Object[] newElements = Arrays.copyOf(elements, len + 1);
            newElements[len] = e;
            setArray(newElements);
            return true;
        } finally {
            lock.unlock();
        }
    }

其添加一个元素的过程如下:
CopyOnWrite 容器即写时赋值容器,往一个容器添加元素时,不直接往当前容器Object[]中加,而是对当前容器object[]进行Copy,复制出一个新的容器Object[] newElements,往新容器里添加元素,添加完毕后,再将原容器的引用指向新的容器setArray(newElemets);好处是可以对CopyOnWrite容器进行并发的读,而不用加锁

2. set不安全

解决思路和list一样,一是Collections.synchronizedList,二是CopyOnWriteArraySet<>();

public class NotSafeDemo2 {
    public static void main(String[] args) {
        Set<String> set = new CopyOnWriteArraySet<>();

        for (int i=0;i<=30;i++){
            new Thread(()->{
                set.add(UUID.randomUUID().toString().substring(0,8));
                System.out.println(set);
            },String.valueOf(i)).start();
        }
    }
}

题外话:HashSet底层是HashMap,为什么Map放<key,value>键值对(两个),但是HashSet只放一个?
因为Set 的add调用的是Map的put方法,Key值就是Set的元素值,value值是PRESENT常量

3. map不安全

用ConcurrentHashMap<>()


public class NotSafeDemo3 {
    public static void main(String[] args) {
        Map<String,String> map = new ConcurrentHashMap<>();

        for (int i=0;i<=30;i++){
            new Thread(()->{
                map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0,8));
                System.out.println(map);
            },String.valueOf(i)).start();
        }
    }
}

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容