JUC并发编程——解决集合类不安全

本文探讨了Java中集合类在多线程环境下存在的安全问题,并介绍了如何通过使用线程安全的集合类如Vector、CopyOnWriteArrayList以及ConcurrentHashMap等来解决这些问题。

JUC并发编程——解决集合类不安全

1、并发集合

在JDK1.5中引入了java.util.concurrent包,在该包中定义了一组线程安全的集合,称为并发集合, 这些集合可以作为同步集合的替代品。

非线程安全的集合并发集合共同接口
ArrayListCopyOnWriteArrayListList
LinkedListConcurrentLinkedQueueQueue
HashSetCopyOnWriteArraySetSet
TreeSetConcurrentSkipListSetSortedSet
HashMapConcurrentHashMapMap
TreeMapConcurrentSkipListMapSortedMap

参考:http://www.bjpowernode.com/javathread/1151.html

2、List 不安全

List集合不是线程安全的,在多线程环境中使用这些集合可能会出现数据不一致的情况,或者产生异常。

public class ListTest {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();

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

查看异常:并发异常 ConcurrentModificationException

在这里插入图片描述

由上可知,并发情况下,ArrayList 不安全。

解决 List 不安全

方法一:Vector 集合

public class ListTest {
    public static void main(String[] args) {
        List<String> list = new Vector<>();

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

原因:Vector集合是线程安全,在Vector集合中使用synchronized关键字把方法修饰为同步方法,只允许由一个线程调用其中一个方法。所以又把Vector集合称为同步集合。

Vector集合add()方法源码:

在这里插入图片描述

方法二:Collections工具类

在Collections工具类中提供了一组synchronizedXXX()方法可以把不是线程安全的集合转换为线程安全的集合,这也是同步集合。

public class ListTest {
    public static void main(String[] args) {
        List<String> list = Collections.synchronizedList(new ArrayList<>());

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

方法三:并发集合CopyOnWriteArrayList,并发集合可以作为同步集合的替代品。

public class ListTest {
    public static void main(String[] args) {
        List<String> list = new CopyOnWriteArrayList<>();

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

CopyOnWriteArrayList 写入操作源码分析:

在这里插入图片描述

CopyOnWriteArrayList集合, 该集合在读取数据时完全不用加锁,并且写操作也不会阻塞读操作。从集合类名来看CopyOnWrite就是在写入操作时,进行一次自我复制。即向集合写入数据并不修改原有的内容, 而是把集合中原来的从容复制到一个副本中,向副本中写入数据,写完后再将副本替换原来的数据。

并发集合CopyOnWriteArrayList 比 同步集合Vector与Collections.synchronizedList() 的效率都要高,因为后两种方法都用了synchronized,每次在读数据时都会进行加锁同步,它们读取数据的效率就低。

3、Set 不安全

和 List集合一样,set集合在并发情况下也是不安全的,

解决Set 不安全两个方法:

1、Collections工具类的 synchronizedSet() 方法

2、并发集合 CopyOnWriteArraySet

4、Map 不安全

public class MapTest {
    public static void main(String[] args) {
        HashMap<Object, Object> map = new HashMap<>();
        for (int i = 1; i < 10; i++) {
            new Thread(() -> {
                map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0, 5));
                System.out.println(map);
            }, String.valueOf(i)).start();
        }
    }
}

发生并发异常:

在这里插入图片描述

解决 Map 不安全

1、Collections 同步集合

public class MapTest {
    public static void main(String[] args) {
        Map<String,String> map = Collections.synchronizedMap(new HashMap<>());

        for (int i = 1; i < 10; i++) {
            new Thread(() -> {
                map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0, 5));
                System.out.println(map);
            }, String.valueOf(i)).start();
        }
    }
}

Collections.synchronizedMap(new HashMap<>()) 可以返回一个线程安全的集合,采用了装饰器模式,在该线程安全的集合内部,先要获得mutex锁,并发效率低。

2、ConcurrentHashMap 集合

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

        ConcurrentHashMap<Object, Object> map = new ConcurrentHashMap<>();
        for (int i = 1; i < 10; i++) {
            new Thread(() -> {
                map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0, 5));
                System.out.println(map);
            }, String.valueOf(i)).start();
        }
    }
}

ConcurrentHashMap是一种高并发的线程安全的 Map集合。在JDK7前,ConcurrentHashMap 集合内部使用粒度极小的锁来保障线程安全,或者说采用了分段锁协议,默认情况下可以支持16个线程并发操作。在JDK8中对ConcurrentHashMap集合进行了性能提升,采用CAS操作实现线程安全。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

万里顾—程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值