Подтвердить что ты не робот

В Java, нужно ли объявлять мою коллекцию синхронизированной, если она доступна только для чтения?

Я заполняю коллекцию один раз, когда запускается мой веб-приложение J2EE. Затем несколько потоков могут получить к нему доступ в одно и то же время, но только для чтения.

Я знаю, что использование синхронизированной коллекции является обязательным для написания параллелей, но мне все еще нужно это для чтения параллелей?

4b9b3361

Ответ 1

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


Примечание: Помните, что, сохраняя коллекцию только для чтения, вы предотвращаете модификации самой коллекции. Каждый элемент коллекции по-прежнему изменчив.

class Test {
    public Test(final int a, final int b) {
        this.a = a;
        this.b = b;
    }

    public int a;
    public int b;
}

public class Main {

    public static void main(String[] args) throws Exception {
        List<Test> values = new ArrayList<Test>(2);
        values.add(new Test(1, 2));
        values.add(new Test(3, 4));

        List<Test> readOnly = Collections.unmodifiableList(values);
        for (Test t : readOnly) {
            t.a = 5;
        }

        for (Test t : values) {
            System.out.println(t.a);
        }
    }

}

Выводится:

5
5

Важные соображения от @WMR answser.

Это зависит от того, будут ли потоки, которые начнется чтение вашей коллекции до или после заполнения. Если они запускаются, прежде чем вы их заполняете, у вас нет гарантий (без синхронизация), что эти потоки когда-либо увидит обновленные значения.

Причиной этого является память Java Модель, если вы хотите узнать больше, прочитайте раздел "Видимость" по этой ссылке: http://gee.cs.oswego.edu/dl/cpj/jmm.html

И даже если потоки запущены после того, как вы заполните свою коллекцию, вы возможно, придется синхронизировать, поскольку реализация коллекции может измениться его внутреннее состояние даже при чтении операции (спасибо Майкл Бар-Sinai, Я не знал таких коллекций существовало).

Еще одно интересное, прочитанное на тема concurrency, которая охватывает такие темы, как публикация объектов, видимость и т.д. намного подробнее книга Брайана Гетца Java concurrency в Практика.

Ответ 2

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

Причиной этого является модель памяти Java, если вы хотите узнать больше, прочитайте раздел "Видимость" по этой ссылке: http://gee.cs.oswego.edu/dl/cpj/jmm.html

И даже если потоки запускаются после заполнения вашей коллекции, вам может потребоваться синхронизация, потому что ваша реализация коллекции может изменить свое внутреннее состояние даже при выполнении операций чтения (спасибо Michael Bar-Sinai, я не знал, что такие коллекции существуют в стандартном JDK).

Еще один интересный текст на тему concurrency, который охватывает такие темы, как публикация объектов, видимость и т.д., гораздо более подробно - книга Брайана Гетца Java concurrency на практике.

Ответ 3

В общем случае, вы должны. Это связано с тем, что некоторые коллекции меняют свою внутреннюю структуру во время чтения. Хорошим примером является LinkedHashMap, который использует порядок доступа. Но не задумывайтесь об этом:

В сопоставленных хэш-картах с привязкой к доступу, просто запрос карты с get является структурной модификацией Связанная хэш-карта javadoc

Если вы абсолютно уверены, что нет кешей, нет статистики статистики, нет оптимизаций, нет забавных вещей вообще - вам не нужно синхронизировать. В этом случае я бы поместил ограничение типа в коллекцию: не объявляйте коллекцию как карту (которая позволит LinkedHashMap), а как HashMap (для пуристов, заключительный подкласс HashMap, но это тоже может быть принято далеко...).

Ответ 4

Вам не обязательно, как объяснено в других ответах. Если вы хотите, чтобы ваша коллекция была доступна только для чтения, вы можете использовать:

yourCollection = Collections.unmodifableCollection(yourCollection);

(аналогичный метод существует для списка, набора, карты и других типов коллекций)

Ответ 5

Сама коллекция не имеет значения, но имейте в виду, что если то, что она имеет, не является неизменным, эти отдельные классы нуждаются в собственной синхронизации.