java集合线程安全解决方案(List,Set,Map)

一丶AarraList : 在多线程下多个线程操作ArrayList, 往里面放入数据或者删除数据输出数据会造成线程不安全。

对于ArrayList解决方案有三种:

1. 使用古老的Vector,Vector相比ArrayList, 它牺牲了性能换取了线程安全.

List<Integer> list = new Vector<>(); //Vector解决List线程安全问题

2. 使用集合工具类Collections里的线程安全方法Collections.synchronizedList()解决

//Collections.synchronizedList解决
List<Integer> list = Collections.synchronizedList(new ArrayList<>());

3. 前面两种基本很少用,都是一些较老的技术,而使用CopyOnWriteArraylist(写时复制技术)来解决线程安全问题是最常用的。

//CopyOnWriteArrayList解决List线程安全问题
List<Integer> list = new CopyOnWriteArrayList<>();

以下就是一个使用CopyOnWriteArrayList的例子

//方法三
        List<Integer> list = new CopyOnWriteArrayList<>(); //CopyOnWriteArrayList解决List线程安全问题
        //创建三个线程往list放数据并输出
        new Thread(() -> {
            for (int i = 0; i < 3; i++) {
                list.add(2);
                System.out.println(list);
            }
        }, "A").start();
        new Thread(() -> {
            for (int i = 0; i < 3; i++) {
                list.add(2);
                System.out.println(list);
            }
        }, "B").start();
        new Thread(() -> {
            for (int i = 0; i < 3; i++) {
                list.add(2);
                System.out.println(list);
            }
        }, "C").start();

控制台输出:

[2] [2, 2] [2, 2, 2] [2, 2, 2, 2] [2, 2, 2, 2, 2] [2, 2, 2, 2, 2, 2] [2, 2, 2, 2, 2, 2, 2] [2, 2, 2, 2, 2, 2, 2, 2] [2, 2, 2, 2, 2, 2, 2, 2, 2]

二丶Set : 使用CopyOnWriteArraySet解决线程安全问题

例子:

//CopyOnWriteArraySet解决set线程安全问题
        Set<Integer> set = new CopyOnWriteArraySet<>();
        //创建三个线程往set放数据并输出
        new Thread(() -> {
            for(int i = 0; i < 3; i ++){
                set.add(i);
                System.out.println(set);
            }
        }, "A").start();
        new Thread(() -> {
            for(int i = 0; i < 3; i ++){
                set.add(i);
                System.out.println(set);
            }
        }, "B").start();
        new Thread(() -> {
            for(int i = 0; i < 3; i ++){
                set.add(i);
                System.out.println(set);
            }
        }, "C").start();

控制台输出:

[0] [0] [0, 1] [0, 1] [0, 1, 2] [0, 1, 2] [0, 1, 2] [0, 1, 2] [0, 1, 2]

三丶Map : 使用ConcurrentHashMap解决线程安全问题

例子:

//ConcurrentHashMap解决map线程不安全问题
        Map<Integer, Integer> map = new ConcurrentHashMap<>();
        //创建三个线程往map里面放入数据并输出
        new Thread(() -> {
            for(int i = 0 ; i < 3; i ++){
                map.put(i, i);
                System.out.println(map);
            }
        }, "A").start();
        new Thread(() -> {
            for(int i = 0 ; i < 3; i ++){
                map.put(i, i);
                System.out.println(map);
            }
        }, "B").start();
        new Thread(() -> {
            for(int i = 0 ; i < 3; i ++){
                map.put(i, i);
                System.out.println(map);
            }
        }, "C").start();

控制台输出:

{0=0} {0=0, 1=1} {0=0, 1=1, 2=2} {0=0, 1=1, 2=2} {0=0, 1=1, 2=2} {0=0, 1=1, 2=2} {0=0, 1=1, 2=2} {0=0, 1=1, 2=2} {0=0, 1=1, 2=2}

总结:

对于List: 可以考虑使用Vector,工具类Collections. synchronizedList()方法,但用得最多的也推荐大家用的是第三种: CopyOnWriteArrayList。

对于Set: 使用CopyOnWriteArraySet。

对于Map: 使用ConcurrentHashMap。

经验分享 程序员 微信小程序 职场和发展