多线程并发下集合不安全类-ArrayList

ArrayList集合在多线程并发操作下是不安全的

ArrayList集合在并发操作下会发生异常:故障现象java.util.ConcurrentModificationException

导致原因 多线程对集合的并发操作导致并发修改异常的产生

解决方案

1、使用Vector(加synchronized)

2、使用集合工具类里的Collections.synchronizedList(new ArrayList<>())使用同步代码块

3、CopyOnWriteArrayList(写时复制ReentrantLock

 

CopyOnWriteArrayList使用的思想是读写分离

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

        //List<String> list = new ArrayList<>();
        //List<String> list = Collections.synchronizedList(new ArrayList<>());
        //collections是集合接口的工具类,collection是集合的接口

        /**
         * 写时复制
         * CopyOnWrite容器即写时复制的容器,往一个容器添加元素的时候,不直接往当前容器object[]
         * 而是先将当前容器object[]进行复制,复制出一个新的object[] new Elements,然后新的容器object[] new Elements里添加元素
         * 添加完元素之后,再将原容器的引用指向新的容器,这样做的好处是可以对容器进行并发的读,
         * 而不需要加锁,因为当前容器不会添加任何元素,所以copyonwrite是一种读写分离的思想,读和写不同的容器
         */
        List<String> list = new CopyOnWriteArrayList<>();

        for (int i = 1; i <= 30; i++) {
            new Thread(()->{
                list.add(UUID.randomUUID().toString().substring(0, 10));
                System.out.println(list);
            }).start();
        
    }
}
package com.zhbit.juc;

import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;

//ArrayList集合类不安全
//故障现象 java.util.ConcurrentModificationException
//导致原因 多线程对集合的并发操作导致并发修改异常的产生
//解决方案 Vector(加synchronized)--->Collections.synchronizedList(new ArrayList<>())使用同步代码块--->CopyOnWriteArrayList(写时复制ReentrantLock)
//优化建议

@Slf4j
public class CopyOnWriteArrayListExample {

    public static void main(String[] args) throws InterruptedException {
        CopyOnWriteArrayListExample.testArrayList();
//        CopyOnWriteArrayListExample.testVector();
//        CopyOnWriteArrayListExample.testCollectionsSynchronizedList();
//        CopyOnWriteArrayListExample.testCopyOnWriteArrayList();
        TimeUnit.SECONDS.sleep(3);
    }


    static void testArrayList() {
        List list = new ArrayList(); //不安全会产生       java.util.ConcurrentModificationException异常
        for (int i = 1; i <= 30; i  ) {
            new Thread(() -> {
                list.add(UUID.randomUUID().toString().substring(0, 8));
                System.out.println(list);
            }, String.valueOf(i)).start();
        }

    }
    
    //以下是三种解决方法
    static void testVector() {
        List list = new Vector();//1、使用Vector代替ArrayList
        for (int i = 1; i <= 30; i  ) {
            new Thread(() -> {
                list.add(UUID.randomUUID().toString().substring(0, 8));
                System.out.println(list);
            }, String.valueOf(i)).start();
        }

    }

    static void testCollectionsSynchronizedList() {
        //2、使用集合工具类的 Collections.synchronizedList解决
        List list = Collections.synchronizedList(new ArrayList<>());
        for (int i = 1; i <= 30; i  ) {
            new Thread(() -> {
                list.add(UUID.randomUUID().toString().substring(0, 8));
                System.out.println(list);
            }, String.valueOf(i)).start();
        }

    }

    static void testCopyOnWriteArrayList() {
        //3、使用CopyOnWriteArrayList(写时复制ReentrantLock)
        List list = new CopyOnWriteArrayList();
        for (int i = 1; i <= 30; i  ) {
            new Thread(() -> {
                list.add(UUID.randomUUID().toString().substring(0, 8));
                System.out.println(list);
            }, String.valueOf(i)).start();
        }

    }
}

 

源码

1、Vector添加操作

使用了synchronized,底层关键字,重量级锁,会阻塞其它线程

/**
     * Appends the specified element to the end of this Vector.
     *
     * @param e element to be appended to this Vector
     * @return {@code true} (as specified by {@link Collection#add})
     * @since 1.2
     */
    public synchronized boolean add(E e) {
        modCount  ;
        ensureCapacityHelper(elementCount   1);
        elementData[elementCount  ] = e;
        return true;
    }

 

2、Collections.synchronizedList添加操作

使用synchronized同步代码块

      public boolean add(E e) {
            synchronized (mutex) {return c.add(e);}
        }

3、CopyOnWriteArrayList的添加操作

使用了ReentrantLock锁,这是JavaAPI层面的锁,属于轻量级的锁,会阻塞其它线程

/**
     * Appends the specified element to the end of this list.
     *
     * @param e element to be appended to this list
     * @return {@code true} (as specified by {@link Collection#add})
     */
    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(); //释放锁
        }
    }

 

ArrayList剖析

底层数据结构: Object类型的数组结构

数组的的默认值:既然底层数据结构是Object类型的数组结构,那么数组是一段连续的内存空间

 

HashSet剖析

底层数据结构: 底层数据结构是HashMap

添加操作

HashSet的添加操作使用的是HashMapput操作,来保证数据的唯一性,因为HashMap的键是不可重复的

 

Collections工具类

 

CopyOnWriteArrayList写时复制

ConcurrentHashMap`底层并不是用写时复制的思想来控制多线程并发安全的,而是直接用`Node`数组 链表 红黑树的数据结构来实现,并发控制使用`Synchronized`和`CAS`来操作,整个看起来就像是优化过且线程安全的`HashMap

 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值