JUC多线程与高并发面试题——ArrayList线程不安全

一、ArrayList线程不安全演示

package com.yuxx.juc;

import java.util.ArrayList;
import java.util.List;

public class ListNotSafeDemo {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        for (int i = 1; i <= 30; i++) {
            new Thread(() -> {
                list.add(1);
                System.out.println(list);
            },String.valueOf(i)).start();
        }
    }
}

由于没有加任何同步锁,多线程情况下抛出了java..util.ConcurrentModificationException。

打印结果:

74f2d2318392e23f9bffa8299b20159add1.jpg

二、ArrayList线程不安全解决办法

2.1 new Vector()

    Vector类的add、removeElement等方法都加了Synchronized同步锁,所以能够实现线程安全。

80375e05dbb2747ae65819e352721fe88d3.jpg55499151dc7017abb76e3f3bb91874e07b1.jpg

    演示:

package com.yuxx.juc;

import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

public class ListNotSafeDemo {
    public static void main(String[] args) {
        List<Integer> list = new Vector<>();
        for (int i = 1; i <= 30; i++) {
            new Thread(() -> {
                list.add(1);
                System.out.println(list);
            },String.valueOf(i)).start();
        }
    }
}

    打印结果:

53a2177d02e743af61ffb703c44c8e3cb2c.jpg

2.2 Collections.synchronizedList(new ArrayList);

    Collections.synchronized方法体:

eb39c17873106f1ec910660e9ac0dd03314.jpg

    再看ArrayList是否是RandomAccess的实例:

e2a3555b63dc9cee57e1d357311bc0f7385.jpg

    所以Collections.synchonized方法中返回的是new SynchronizedRandomAccessList()。

    SynchronizedRadomAccessList是Collections的一个静态内部类,继承了SynchronizedList类,而SynchronizedRadomAccessList本身没有几个实现方法,所以大部分还是使用SynchronizedList方法里的方法。

f23584d6bfb15a7c18729a68b298c7da8d9.jpg

    SynchronizedList的方法里,都有synchronized修饰,保证了线程安全:

7ca20384a62b56fe2c22c2d446e7a57a182.jpg

2.3 new CopyOnWriteArrayList()

    写时复制:CopyOnWrite容器即写时复制容器。往一个容器添加元素的时候,不直接往当前容器Object[]添加。而是先将当前的Object[]进行copy,复制出一个新的容器Object[] newElements。然后新的容器Object[] newElements里添加元素,添加完元素之后,再将原容器的引用指向新的容器setArray(newElements)。

    这样做的好处是,可以对CopyOnWrite容器进行并发的读,而不需要加锁。因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。

    CopyOnWriteArrayList.add实例方法,就是通过可重入锁锁住增加元素代码,然后先复制集合,写入,重新指向:

4ce25b08bfd68b7f2393a86bbf28eda8da1.jpg

 

转载于:https://my.oschina.net/alexjava/blog/3101056

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值