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多线程之集合类(线程安全和不安全)》

解决办法:
  • 使用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多线程之集合类(线程安全和不安全)》

小结:

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

3.解析CopyOnWrite容器

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

源码部分如下
《Java多线程之集合类(线程安全和不安全)》

其中的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多线程之集合类(线程安全和不安全)》
  1. 你可能会想,HashSet是一个参数,而HashMap是键值对存在的。那是因为HashSet只用了HashMap是键,它的值是一个固定的Object对象。
    《Java多线程之集合类(线程安全和不安全)》
    《Java多线程之集合类(线程安全和不安全)》
    原文作者:娃哈哈、
    原文地址: https://blog.csdn.net/weixin_41910694/article/details/90207706
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞