MST
星途 面试题库

面试题:Java Collections框架中,CopyOnWriteArrayList与Vector在同步机制上的区别?

CopyOnWriteArrayList和Vector都是Java Collections框架中线程安全的List实现。请深入分析它们在同步机制、性能、适用场景等方面的区别,并举例说明在何种情况下应优先选择使用哪一个。
36.8万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

同步机制

  • CopyOnWriteArrayList:采用写时复制的策略。在执行写操作(如add、set等)时,会先复制一份原数组,在新数组上进行操作,操作完成后将原数组引用指向新数组。读操作(如get)则直接读取原数组,无需加锁。这使得读操作是线程安全且无锁的,提高了读性能。
  • Vector:使用synchronized关键字对几乎所有的方法(如add、get、remove等)进行同步,确保同一时间只有一个线程能访问Vector,实现线程安全。

性能

  • 读性能
    • CopyOnWriteArrayList:由于读操作无锁,在高并发读场景下性能非常好。读操作不会被写操作阻塞。
    • Vector:由于方法都加锁,读操作会受锁的影响,在高并发读场景下性能不如CopyOnWriteArrayList。
  • 写性能
    • CopyOnWriteArrayList:写操作时要复制数组,开销较大,尤其是数组元素较多时。每次写操作都要进行数组复制和内存分配,性能较低。
    • Vector:虽然写操作加锁,但相比CopyOnWriteArrayList不需要复制数组,在写操作不频繁时,性能可能优于CopyOnWriteArrayList。

适用场景

  • CopyOnWriteArrayList:适用于读多写少的场景,例如配置信息的读取,数据一旦初始化很少修改,但可能被多个线程频繁读取。
  • Vector:适用于读写比较均衡,或者写操作相对较多,且对数据一致性要求较高的场景。比如在一些简单的多线程数据处理场景,对性能要求不是极致高,同时需要保证数据一致性。

举例

假设我们有一个应用程序,需要维护一个全局的配置信息列表,这个列表在系统启动时初始化,之后很少修改,但在运行过程中会被大量线程频繁读取。这种情况下优先选择CopyOnWriteArrayList。

示例代码:

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

public class ConfigReader {
    private static final List<String> configList = new CopyOnWriteArrayList<>();

    static {
        // 初始化配置
        configList.add("config1");
        configList.add("config2");
    }

    public static String getConfig(int index) {
        return configList.get(index);
    }
}

如果是一个简单的多线程任务队列,任务的添加和获取操作频率差不多,且需要严格保证数据一致性,那么选择Vector更合适。

示例代码:

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

public class TaskQueue {
    private static final List<String> taskList = new Vector<>();

    public static void addTask(String task) {
        taskList.add(task);
    }

    public static String getTask() {
        if (!taskList.isEmpty()) {
            return taskList.remove(0);
        }
        return null;
    }
}