Как вернуть потокобезопасную / неизменяемую коллекцию в Java?

В проекте, который я пишу, мне нужно вернуть потокобезопасное и неизменное представление из функции. Однако я не уверен в этом. поскольку synchronizedList а также unmodifiableList просто вернуть представления списка, я не знаю, если

Collections.synchronizedList(Collections.unmodifiableList(this.data));

сделал бы трюк.

Может ли кто-нибудь сказать мне, если это правильно, и если это не так, есть ли ситуации, которые это может потерпеть неудачу?

Спасибо за любые вклады!

6 ответов

Решение

Я считаю, что это настоящий пробел в JDK. К счастью, команда Google, возглавляемая дизайнером Java Collections Джошуа Блохом, создала библиотеку, которая включает в себя действительно неизменные коллекции.

В частности, ImmutableList - это та реализация, которую вы ищете. Вот краткий набросок некоторых функций ImmutableCollections Guava.

Я думаю, что немодифицируемого достаточно. Вы не можете писать в него, что вызывает проблемы для многопоточного доступа. Это только для чтения, поэтому дополнительный шаг синхронизации кажется мне ненужным.

Лучше всего проверить исходный код, когда есть такие вопросы. Похоже, это возвращает UnmodifiableList:

/**
 * @serial include
 */
static class UnmodifiableList<E> extends UnmodifiableCollection<E>
                  implements List<E> {
    static final long serialVersionUID = -283967356065247728L;
final List<? extends E> list;

UnmodifiableList(List<? extends E> list) {
    super(list);
    this.list = list;
}

public boolean equals(Object o) {return o == this || list.equals(o);}
public int hashCode()       {return list.hashCode();}

public E get(int index) {return list.get(index);}
public E set(int index, E element) {
    throw new UnsupportedOperationException();
    }
public void add(int index, E element) {
    throw new UnsupportedOperationException();
    }
public E remove(int index) {
    throw new UnsupportedOperationException();
    }
public int indexOf(Object o)            {return list.indexOf(o);}
public int lastIndexOf(Object o)        {return list.lastIndexOf(o);}
public boolean addAll(int index, Collection<? extends E> c) {
    throw new UnsupportedOperationException();
    }
public ListIterator<E> listIterator()   {return listIterator(0);}

public ListIterator<E> listIterator(final int index) {
    return new ListIterator<E>() {
    ListIterator<? extends E> i = list.listIterator(index);

    public boolean hasNext()     {return i.hasNext();}
    public E next()          {return i.next();}
    public boolean hasPrevious() {return i.hasPrevious();}
    public E previous()      {return i.previous();}
    public int nextIndex()       {return i.nextIndex();}
    public int previousIndex()   {return i.previousIndex();}

    public void remove() {
        throw new UnsupportedOperationException();
            }
    public void set(E e) {
        throw new UnsupportedOperationException();
            }
    public void add(E e) {
        throw new UnsupportedOperationException();
            }
    };
}
Collections.unmodifiableList(this.data) 

Сделаем, как вернем взгляд. Любые попытки изменения в этом представлении приведут к UnsupportedOperationException быть брошенным Ниже приведены выдержки из Collections#unmodifiableList документация.

Возвращает неизменяемое представление указанного списка. Этот метод позволяет модулям предоставлять пользователям доступ "только для чтения" к внутренним спискам. Операции запроса в возвращаемом списке "считываются" в указанный список и пытаются изменить возвращенный список, будь то прямой или через его итератор, приводят к исключению UnsupportedOperationException.

......

java 8 java.util.Collections javadoc

copyOf

Да, теперь встроен в Java 10 и новее.

Каждый из них возвращает отдельную коллекцию объектов, найденных в оригинале. Возвращенная коллекция не является видом на оригинал, как в случае сCollections.unmodifiable… методы служебного класса.

Java 9+ ImmutableCollections является потокобезопасным. Например, List.of, Map.of ... Согласно документу oracle,

Одним из преимуществ неизменяемой коллекции является то, что она автоматически потокобезопасна. После создания коллекции вы можете передать ее нескольким потокам, и все они будут видеть согласованное представление.

Подробнее на: oracle docs

Эти представления не вернут вам действительно поточно-ориентированные коллекции. Всегда существует вероятность того, что кто-либо изменит базовую коллекцию или элементы коллекции.

Чтобы решить эту проблему, вам нужно использовать неизменяемые коллекции и неизменные элементы. Затем в результате возникает потокобезопасность.

Clojure содержит такие неизменные (или постоянные) коллекции.

Проще говоря, добавление или удаление новых элементов возвращает новую коллекцию, которая, как правило , повторно использует большие части старой коллекции посредством умного использования структур данных типа Trie.

Сами по себе они плохо подходят для использования на прямой Java.

Pure4j - это попытка перенести их (и стиль, основанный на неизменности / ценности, поддерживаемый Clojure) на язык Java. Это может быть то, что вы после.

Отказ от ответственности: я разработчик Pure4J

Другие вопросы по тегам