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

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

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

Ответы [ 5 ]

19 голосов
/ 30 сентября 2008

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


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

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 answer.

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

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

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

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

10 голосов
/ 30 сентября 2008

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

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

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

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

9 голосов
/ 30 сентября 2008

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

В упорядоченных связанных хеш-картах простой запрос карты с помощью get является структурной модификацией. Javadoc связанной хэш-карты

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

3 голосов
/ 30 сентября 2008

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

yourCollection = Collections.unmodifableCollection(yourCollection);

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

0 голосов
/ 30 сентября 2008

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...