Возвращение массивов Java против коллекций - PullRequest
3 голосов
/ 23 марта 2011

Я пытаюсь продумать какой-то дизайн в отношении выделения памяти и многопоточности в Java-приложении, и вот что мне интересно:

У меня есть класс, у которого есть синхронизированная коллекция, скажем, список, который обновляется несколько раз в секунду, но все обновления происходят внутри класса и его собственного потока, а не из других потоков. Однако у меня есть много других потоков, которые вызывают метод getCollection () и делают foreach для итерации его содержимого только для чтения. Вот чего я не знаю:

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

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

Кроме того, если я никогда не верну саму коллекцию, тогда синхронизировать список больше не нужно?

Буду признателен за любой вклад. Спасибо! - Дункан

Ответы [ 4 ]

10 голосов
/ 23 марта 2011

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

Если вы говорите о синхронизированных (не одновременных) коллекциях, тогда да. Что касается второго вопроса, это выглядит как реальный вариант использования для java.util.concurrent.CopyOnWriteArrayList.

6 голосов
/ 23 марта 2011

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

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

Вместо этогосоздания копии каждый раз, когда вызывается getCollection, вы создаете копию каждый раз, когда коллекция модифицируется (гораздо реже). Это то, что COWAL делает для вас.

Если вы вернете копию по требованию, выеще нужно синхронизировать коллекцию.

2 голосов
/ 23 марта 2011

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

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

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

0 голосов
/ 23 марта 2011

Кажется, что коллекции часто обновляются и часто вызывается #getCollection (). Вы можете использовать CopyOnWriteArrayList, но вы будете создавать копию каждый раз, когда изменяете массив. Так что вам нужно посмотреть, как это влияет на производительность.

Другой вариант - поручить потоку внутри класса делать копию каждый раз, когда вызывается #getCollection. Это потребует #getCollection, ожидающего завершения внутреннего потока класса.

Если вы просто хотите, чтобы #getCollection возвращала недавнюю копию, а не самую последнюю, тогда внутренний поток может периодически создавать копию коллекции, которая возвращается в #getCollection. Копия должна быть изменчивой или иметь AtomicReference.

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