关于java:6ArrayList线程安全问题

题出问题

咱们晓得ArrayList是线程不平安,请编写一个不平安的案例并给出解决方案?

单线程环境

单线程环境的ArrayList是不会有问题的

public class ArrayListNotSafeDemo {
    public static void main(String[] args) {

        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");

        for(String element : list) {
            System.out.println(element);
        }
    }
}

多线程环境

为什么多线程环境下ArrayList是线程不平安的?因为在进行写操作(add办法)的时候,办法上为了保障并发性,没有增加synchronized润饰。

当咱们同时启动30个线程去操作List的时候

public class Test {
    public static void main(String[] args) {

        List<String> list = new ArrayList<>();

        for (long i = 0; i < 30; i++) {
            new Thread(() -> {

                list.add("hello");
                list.add("world");
                list.add("java");
                System.out.println(list);

            }).start();
        }

    }
}

咱们运行发现报了java.util.ConcurrentModificationException(并发批改的异样)

解决方案

计划一:Vector

采纳Vector实现线程平安,Vector在办法上加了锁,即synchronized

这样就每次只可能一个线程进行操作,所以不会呈现线程不平安的问题,然而因为加锁了,导致并发性降落。

计划二:Collections.synchronized()

List<String> list = Collections.synchronizedList(new ArrayList<>());

采纳Collections汇合工具类,在ArrayList里面包装一层 同步 机制

计划三:采纳JUC外面的办法

CopyOnWriteArrayList:写时复制,次要是一种读写拆散的思维。

  • 就是写的时候,把ArrayList扩容一个进去,而后把值填写下来,在告诉其余的线程,ArrayList的援用指向扩容后的。
  • CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
查看add办法源码

  1. 首先须要加锁

    final ReentrantLock lock = this.lock;
    lock.lock();
  2. 而后在开端扩容一个单位

    Object[] elements = getArray();        
    int len = elements.length;
    Object[] newElements = Arrays.copyOf(elements, len + 1);//扩容一个单位,复制到新数组
  3. 而后在把扩容后的空间,填写上须要add的内容

    newElements[len] = e;
  4. 最初把内容set到Array中

利用场景:个别用于黑/白名单,这样的中央,规范的读多写少场景

HashSet线程不平安

CopyOnWriteArraySet(底层还是用的CopyOnWriteArrayList)

HashMap线程不平安

  1. 应用Collections.synchronizedMap(new HashMap<>())
  2. 应用ConcurrentHashMap

    Map<String, String> map = new ConcurrentHashMap<>();

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理