并发ArrayList

时间:2014-10-17 11:26:15

标签: java arraylist concurrency

我需要一个类似ArrayList的结构,只允许以下操作

  • get(int index)
  • add(E element)
  • set(int index, E element)
  • iterator()

由于在许多地方使用迭代器,因此使用Collections#synchronizedList会容易出错。该列表可以增长到几千个元素并且会被大量使用,所以我很确定CopyOnWriteArrayList会太慢。我会从它开始,以避免过早的优化,但我敢打赌它不会很好地工作。

大多数访问都是单线程读取。所以我问这个适当的数据结构是什么。


我虽然将synchronizedList包装在提供同步迭代器的东西中会有所作为,但由于ConcurrentModificationException它不会成功。对于并发行为,我显然需要后续读取和迭代器可以看到所有更改。

迭代器不必显示一致的快照,它可能会或不会通过set(int index, E element)看到更新,因为此操作仅用于替换具有更新版本的项目(包含一些附加信息) ,这与迭代器的用户无关)。这些项目是完全不可变的。


我清楚地说明为什么CopyOnWriteArrayList不会这样做。由于缺少索引访问权限,ConcurrentLinkedQueue是不可能的。我只需要几个操作而不是完全成熟的ArrayList。因此,除非任何与Java并发列表相关的问题与this question重复,否则此问题不是。{/ p>

1 个答案:

答案 0 :(得分:7)

在您的情况下,您可以使用ReadWriteLock访问支持的列表,这允许多个线程读取您的列表。只有当一个线程需要写访问时,所有读者 - 线程必须等待操作完成。 JavaDoc明确指出:

  

ReadWriteLock维护一对关联的锁,一个用于   只读操作和写操作。可以保持读锁定   同时由多个读者线程,只要没有   作家。写锁是独占的。

以下是一个示例:

public class ConcurrentArrayList<T> {

    /** use this to lock for write operations like add/remove */
    private final Lock readLock;
    /** use this to lock for read operations like get/iterator/contains.. */
    private final Lock writeLock;
    /** the underlying list*/
    private final List<T> list = new ArrayList();

    {
        ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
        readLock = rwLock.readLock();
        writeLock = rwLock.writeLock();
    }

    public void add(T e){
        writeLock.lock();
        try{
            list.add(e);
        }finally{
            writeLock.unlock();
        }
    }

    public void get(int index){
        readLock.lock();
        try{
            list.get(index);
        }finally{
            readLock.unlock();
        }
    }

    public Iterator<T> iterator(){
        readLock.lock();
        try {
            return new ArrayList<T>( list ).iterator();
                   //^ we iterate over an snapshot of our list 
        } finally{
            readLock.unlock();
        }
    }