MST
星途 面试题库

面试题:Java Collections工具类线程安全集合包装方法与并发包下其他线程安全集合的对比

Java Collections工具类的线程安全集合包装方法(如Collections.synchronizedList()等)和java.util.concurrent包下的线程安全集合(如CopyOnWriteArrayList等)在实现机制、适用场景、内存开销和线程安全性等方面有何异同?请深入分析并举例说明在不同业务场景下如何选择使用。
33.6万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

实现机制

  • Collections工具类线程安全集合包装方法:通过在集合的方法中添加synchronized关键字,对方法进行同步控制,每次只能有一个线程访问集合的方法。例如Collections.synchronizedList(new ArrayList<>()),在对该列表进行操作(如addremove等)时,会同步执行。
  • java.util.concurrent包下的线程安全集合
    • CopyOnWriteArrayList:写操作时,会复制一份原数组,在新数组上进行修改,最后将原数组引用指向新数组。读操作直接读取原数组,不需要加锁,这使得读操作性能较高。
    • ConcurrentHashMap:在JDK1.7中采用分段锁机制,将哈希表分为多个段(Segment),每个段有自己的锁,不同段的写操作可以并发执行;JDK1.8中采用CAS + synchronized来实现,减少锁的粒度,提高并发性能。

适用场景

  • Collections工具类线程安全集合包装方法:适用于读多写少,并且对性能要求不是特别高的场景。例如在一些简单的多线程数据统计场景中,操作频率不高,对性能要求相对较低。
  • java.util.concurrent包下的线程安全集合
    • CopyOnWriteArrayList:非常适合读操作远多于写操作的场景,如事件监听列表。因为读操作无锁,性能好,但写操作因数组复制开销大。
    • ConcurrentHashMap:适用于高并发读写的场景,如在高并发的Web应用中存储用户会话信息等,能提供较好的并发性能。

内存开销

  • Collections工具类线程安全集合包装方法:内存开销相对较小,因为只是在原集合基础上添加同步控制,没有额外复杂的数据结构。
  • java.util.concurrent包下的线程安全集合
    • CopyOnWriteArrayList:写操作时会复制数组,内存开销较大,特别是当集合元素较多时。
    • ConcurrentHashMap:为了实现并发控制,会有一些额外的数据结构开销,如JDK1.7中的Segment数组等,但相比CopyOnWriteArrayList在写时的数组复制开销,在整体内存使用上会根据具体使用情况有所不同。

线程安全性

  • Collections工具类线程安全集合包装方法:线程安全,通过synchronized保证了同一时间只有一个线程能访问集合方法,但在迭代集合时(如使用Iterator),若不手动同步,仍然可能出现ConcurrentModificationException,需要在迭代时手动同步集合。例如:
List<String> synchronizedList = Collections.synchronizedList(new ArrayList<>());
synchronizedList.add("a");
synchronizedList.add("b");
synchronized (synchronizedList) {
    Iterator<String> iterator = synchronizedList.iterator();
    while (iterator.hasNext()) {
        System.out.println(iterator.next());
    }
}
  • java.util.concurrent包下的线程安全集合
    • CopyOnWriteArrayList:线程安全,读操作无锁,写操作通过复制数组保证数据一致性,迭代器不会抛出ConcurrentModificationException,因为迭代的是旧数组。
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
list.add("a");
list.add("b");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    System.out.println(iterator.next());
}
- **ConcurrentHashMap**:线程安全,在高并发环境下能保证数据的一致性和线程安全,通过锁分段或CAS + synchronized机制实现。

不同业务场景下的选择

  • 读多写少且性能要求一般:选择Collections.synchronizedList等包装方法,如在一些简单的日志记录场景,记录操作频率不高,对性能要求不是特别苛刻。
  • 读操作远多于写操作:选择CopyOnWriteArrayList,例如在事件监听器列表中,注册和注销监听器(写操作)频率低,而事件触发时遍历监听器列表(读操作)频率高。
  • 高并发读写场景:选择ConcurrentHashMap,比如在高并发的电商系统中统计商品浏览量等场景,需要频繁进行读写操作。