Параллельный массив ArrayList

Мне нужна структура, подобная 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-параллельный вопрос, связанный с списком, является дубликатом этого вопроса, этого нет.

Ответы

Ответ 1

В вашем случае вы можете использовать ReadWriteLock для доступа к резервному списку, это позволяет нескольким потокам читать ваш список. Только если один поток нуждается в доступе на запись, все считыватели-Thread должны дождаться завершения операции. 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();
        }
    }