多线程下List 如何解决不安全问题

什么是线程安全与不安全

线程安全:就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。

线程不安全:就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据

为什么Lis是不安全的呢?show code

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

结果是
java.util.ConcurrentModificationException

为社么会这样?看看源码

public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

我们可以看到,当添加元素之后,size还没有加加,如果此时另一个线程抢夺了cpu的资源,进行添加元素操作,size现在也是为0,然后之前的线程两个线程继续执行,结果就是有两个元素添加进去,但是当前容量为却是1.明白了吗

那么如何解决呢?
使用 Vector
为什么vector可以呢,看看源码

public synchronized boolean add(E e) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = e;
        return true;
    }

还可以有其他方式吗?
可以的,使用集合工具类 Collections.synchronizedList(new ArrayList<>()) 就可以创建一个安全的list,看看源码是怎么实现的

 public void add(int index, E element) {
            synchronized (mutex) {
          		  list.add(index, element);
            }
        }

你说如果不想使用这个,还有没有其他的方法,还有哦
在java.util.concurrent的包下有 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();
        }
    }

map 和 set 也存在不安全问题哦,解决方式也类似

猜你喜欢

转载自blog.csdn.net/qq_42224683/article/details/107335381