Java: большая коллекция и параллельные потоки

Я столкнулся с этой проблемой: у меня много потоков (1024), которые обращаются к одной большой коллекции - Vector. Вопрос: можно ли что-то с этим сделать, что позволило бы мне выполнять с ним одновременные действия без необходимости все синхронизировать (поскольку это требует времени)? Я имею в виду, что работает что-то вроде базы данных Mysql, вам не нужно беспокоиться о синхронизации и проблемах с потокобезопасностью. Есть ли аналогичная коллекция в Java? Спасибо


person Andrey    schedule 18.12.2009    source источник
comment
Почему у вас 1024 потока? Это безумие.   -  person Mark Byers    schedule 18.12.2009
comment
У меня 8-ядерный процессор и 8 ГБ ОЗУ, и 3000 пользователей обращаются к моему приложению, так что я думаю, что это нормально, не так ли?   -  person Andrey    schedule 18.12.2009
comment
@Mark: Не обязательно, это просто очень высокая степень параллелизма. Однако 1024 потока на 8 ядрах, вероятно, избыточны.   -  person skaffman    schedule 18.12.2009
comment
Делают ли потоки изменения в Векторе или просто читают из него? Как только потоки начнут выполнять свои операции, изменится ли размер вектора? Модель set-lock, которую использует Java, будет проблемой, но есть способы спроектировать ваше приложение, чтобы оно было потокобезопасным без этих шагов.   -  person James Black    schedule 18.12.2009
comment
Я предлагаю получить копию Java Concurrency in Practice.   -  person lemon    schedule 18.12.2009
comment
все, что делает поток, - это добавление элементов в вектор (только если количество элементов в векторе = 0) и удаление элементов из вектора. (если размер вектора › 0)   -  person Andrey    schedule 18.12.2009
comment
Подождите... эти потоки обращаются с вашим вектором как с очередью?   -  person PSpeed    schedule 18.12.2009


Ответы (5)


Vector — это очень старый класс Java, предшествующий API коллекций. Он синхронизируется при каждой операции, поэтому вам не повезет, если вы попытаетесь его ускорить. Вам следует подумать о переработке своего кода, чтобы использовать что-то вроде ConcurrentHashMap или LinkedBlockingQueue, которые очень оптимизированы для одновременного доступа.

В противном случае вы упоминаете, что хотели бы производительность и семантику доступа, аналогичную базе данных - почему бы не использовать выделенную базу данных или очередь сообщений? Скорее всего, они реализуют его лучше, чем вы когда-либо, и вам придется писать меньше кода!

[править] Учитывая ваш комментарий:

all what thread does is adding elements to vector 
(only if num of elements in vector = 0) & 
removing elements from vector. (if vector size > 0)

это звучит очень похоже на то, что вы должны использовать что-то гораздо больше похожее на очередь, чем на список! Ограниченная очередь размером 1 даст вам эту семантику, хотя я бы спросил, почему вы не можете добавлять элементы, если там уже что-то есть. Когда у вас тысячи потоков, это кажется очень неэффективным дизайном.

person Steven Schlansker    schedule 18.12.2009

Ну, во-первых, этот дизайн звучит неправильно. Похоже, вам нужно подумать об использовании правильной базы данных, а не простой структуры данных, даже если это означает просто использование чего-то вроде экземпляра в памяти HysonicDB.

Однако, если вы настаиваете на этом, то java.util.concurrent имеется ряд высококонкурентных неблокирующих структур данных. Один из них может подойти для ваших целей (например, ConcurrentHashMap, если вы можете использовать Map вместо List)

person skaffman    schedule 18.12.2009
comment
-1: Учитывая его комментарий об использовании Вектора, я думаю, что ответ Стивена Шланскера о рассмотрении очереди гораздо более уместен. - person Tuure Laurinolli; 19.12.2009
comment
Вы отрицаете ответ, если считаете его плохим, а не потому, что считаете другой ответ лучше. - person skaffman; 19.12.2009

Похоже, вы реализуете шаблон производителя-потребителя, вам следует поискать в Google «производитель-потребитель java» или посмотреть интерфейс BlockingQueue

person pgras    schedule 18.12.2009

Я согласен со скаффманом по поводу просмотра java.util.concurrent.

ConcurrentHashMap очень масштабируем. Однако вызов size() возвращает только приблизительное значение. Так, например. ваше приложение будет время от времени добавлять к нему элементы, даже если !(количество элементов в векторе = 0).

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

Вместо того, чтобы иметь тонны переключений контекста, я думаю, вы могли бы позволить своим пользователям размещать вызываемый объект в очереди и иметь только один поток, занимающийся мутацией. Это устранит необходимость синхронизации в коллекции. Пользовательские потоки могут ожидать Future.get().

Просто идея.

person Enno Shioji    schedule 19.12.2009

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

Но вы должны проверить, подходит ли используемая структура данных для задачи, или другой из многих классов java.util или java.util.concurrent более подходит. Между прочим, java.util.Vector синхронизирован.

person Hans-Peter Störr    schedule 20.12.2009