Java多线程之集合类(线程安全和不安全)

Java多线程之集合类(浅析线程安全和不安全)


本文目录:

  • 1.线程不安全之ArrayListHashSetHashMap和线程安全之CopyOnWriteArrayListCopyOnWriteArraySetConcurrentHashMap
  • 2. 小结
  • 3.解析CopyOnWrite容器

1.线程不安全之ArrayList和线程安全之CopyOnWriteArrayList


测试代码:

  • 多个线程往一个集合中添加内容。
实现:
public static void listNotSafe() {
     
        List<String> list = new ArrayList<>();
        for (int i = 1; i <= 30 ; i++) {
     
            new Thread(()->{
     
                list.add(UUID.randomUUID().toString().substring(0,6));
                System.out.println(list);
            },String.valueOf(i)).start();
        }

编译结果:
Java多线程之集合类(线程安全和不安全)_第1张图片


解决办法:
  • 使用CopyOnWriteArrayList代替ArrayList

使用如下:

public static void listNotSafe() {
     
        List<String> list = new CopyOnWriteArrayList<>();
        for (int i = 1; i <= 30 ; i++) {
     
            new Thread(()->{
     
                list.add(UUID.randomUUID().toString().substring(0,6));
                System.out.println(list);
            },String.valueOf(i)).start();
        }

编译结果:
Java多线程之集合类(线程安全和不安全)_第2张图片


小结:

  • 1. 经过测试,发现HashSetHashMap也是线程不安全的,分别对应的解决办法是用CopyOnWriteArraySetConcurrentHashMap替换(如上面的例子)


3.解析CopyOnWrite容器

  • 我们发现CopyOnWrite容器能够解决线程不安全的问题,现在来通过源码进行解析(以CopyOnWriteArrayList)为例。

源码部分如下
Java多线程之集合类(线程安全和不安全)_第3张图片


其中的add(E e)方法
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();
		    }
		}

可以知道:

  1. 都是有线程锁的,所以是线程安全的
  2. CopyOnWrite容器即写时复制的容器。往一个容器添加元素的时候,不直接往当前容器Object[ ]添加,而是先将当前容器Object[ ]进行Copy,复制出一个新的容器Object[] newElements,然后往新的容器Object[ ] newElements里添加元素,添加完元素之后,再将原容器的引用指向新的容器 setArray(newElements)。
  3. 好处是可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器

扩展小知识:

  1. HashSet底层是HashMap
    Java多线程之集合类(线程安全和不安全)_第4张图片

  1. 你可能会想,HashSet是一个参数,而HashMap是键值对存在的。那是因为HashSet只用了HashMap是键,它的值是一个固定的Object对象。
    Java多线程之集合类(线程安全和不安全)_第5张图片
    在这里插入图片描述

你可能感兴趣的:(java多线程,多线程)