Итерация многопоточного списка без синхронизации всего процесса

1

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

Будет много итераций, поэтому я не могу поставить синхронизацию вне цикла следующим образом:

synchronized (list) {
    Iterator i = list.iterator();
    //Must be in synchronized block
    while (i.hasNext())
        foo(i.next());
}

потому что я потеряю преимущество многопоточности. И размер моих списков может составить около 1000, поэтому я не могу заблокировать весь список, пока итерация на всех этих элементах

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

Итак, какое наилучшее решение для использования в такой ситуации, как моя

  • 1
    Примечание: я рекомендую использовать пробелы (но на самом деле это редактор, который автоматически отступает и добавляет пробелы при нажатии табуляции), а не табуляции. Это также облегчает копирование в SO.
  • 2
    Таким образом, у вас есть ситуация, которая требует высокой степени параллелизма, но также требует, чтобы вы перебирали весь список объектов. Честно говоря, вы должны разработать свою программу так, чтобы она могла быть сделана одновременно. На самом деле, мы знаем только, что вам нужно перебрать список, поэтому это все, что мы можем вам посоветовать.
Показать ещё 2 комментария
Теги:
list
multithreading
iterator
synchronization

1 ответ

2
Лучший ответ

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

Подумайте об этом таким образом. Итерация потока по списку и поток, изменяющий список, могут чередовать их операции различными способами, ни одна из которых не является ошибкой. Одна из возможностей заключается в том, что итерационная нить может перебираться по всему списку до того, как будет запущен модифицирующий поток. Другая возможность заключается в том, что итерационный поток будет попадать наполовину через список до его изменения. Распространение изменений на все существующие итераторы было бы сложной и дорогостоящей операцией, и вам нужно было бы тщательно определить, что делает итератор, например, когда что-то вставлено ниже его текущей позиции. И вся эта сложность не сделала бы программу более правильной, потому что поведение было бы идентично CopyOnWriteArrayList если бы потоки просто планировались несколько иначе.

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

  • 0
    Следует отметить (из документа Java): «Это обычно слишком дорого, но может быть более эффективным, чем альтернативы, когда операции обхода значительно превосходят количество мутаций»
  • 0
    @Kevin Я действительно запутался, не могли бы вы объяснить свой ответ примером, чтобы я мог понять, как мне использовать этот шаблон
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню