Java 中的 CopyOnWriteArrayList

CopyOnWriteArrayList 是 Java 中的一个类,是“java.util.concurrent”包的一部分。它是“ArrayList”类的线程安全变体。CopyOnWriteArrayList 的关键特性是它提供了一种无需显式同步即可实现线程安全的方法。

以下是 CopyOnWriteArrayList 的工作原理:

1. 写入时复制策略:当在“CopyOnWriteArrayList”中添加、修改或删除元素时,会创建底层数组的新副本。然后用所需的更改修改此新副本。此策略可确保原始数组保持不变,从而为任何当前迭代线程提供一致的数据视图。

2. 读取是非阻塞的:读取操作(例如“get”和“iterator”)对当前底层数组进行操作,无需获取任何锁。这使得读取操作非常快,适合读取比写入更频繁的情况。

3. 迭代器是快照迭代器: “CopyOnWriteArrayList”返回的迭代器会遍历创建迭代器时列表的元素。它们不反映对该列表所做的任何后续更改。此行为与“快照”样式迭代器一致。

由于这些特性,“CopyOnWriteArrayList”在读取比写入频繁得多且在每个写入操作上创建数组的新副本的开销可以接受的情况下特别有用。

需要注意的是,虽然“CopyOnWriteArrayList”为某些用例提供了线程安全性,但它可能并不适合所有场景。对于列表很少被修改的情况,与读取操作的数量相比,它的效率更高。

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

public class ExampleMain{
    public static void main(String[] args) throws InterruptedException {
        // Creating a CopyOnWriteArrayList
        List<String> copyOnWriteList = new CopyOnWriteArrayList<>();

       
// 向列表添加元素
        copyOnWriteList.add(
"Java");
        copyOnWriteList.add(
"Python");
        copyOnWriteList.add(
"C++");
        copyOnWriteList.add(
"JavaScript");

       
// 创建读取元素的线程
        Thread readerThread = new Thread(() -> {
            Iterator<String> iterator = copyOnWriteList.iterator();
            while (iterator.hasNext()) {
                String language = iterator.next();
                System.out.println(
"readerThread Reading: " + language);
                try {
                   
// Introducing a delay to simulate other operations
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

       
// Creating a thread for writing (modifying) the list
        Thread writerThread = new Thread(() -> {
           
// 通过添加新元素修改列表
            copyOnWriteList.add(
"Ruby");
            System.out.println(
"writerThread Added: Ruby");
            System.out.println(copyOnWriteList);

            try {
               
// 引入延迟以模拟其他操作
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

           
// 通过删除一个元素来修改列表
            copyOnWriteList.remove(
"C++");
            System.out.println(
"writerThread Removed: C++");
            System.out.println(copyOnWriteList);
        });

       
// Starting both threads
        readerThread.start();
        writerThread.start();
    }
}

在本例中,"CopyOnWriteArrayList "用于存储编程语言列表。读取器线程 "模拟对列表的连续读取操作,而 "写入器线程 "则执行延迟写入操作(添加和删除),以展示 "CopyOnWriteArrayList "的线程安全性。顾名思义,在进行写操作时,会复制底层数组,确保读取不受正在进行的写操作的影响。

请记住,"CopyOnWriteArrayList "对于读取次数多、写入次数少的场景非常高效,但对于写入操作频繁的场景,由于创建数组副本的开销,它可能不是最佳选择。