1) Це CopyOnWriteArraySet
досить проста реалізація - вона в основному має список елементів у масиві, а при зміні списку копіює масив. Ітерації та інші звернення, що працюють у цей час, тривають зі старим масивом, уникаючи необхідності синхронізації між читачами та письменниками (хоча саме написання потрібно синхронізувати). Нормально швидкі задані операції (особливо contains()
) тут досить повільні, оскільки масиви будуть шукати в лінійний час.
Використовуйте це лише для дійсно невеликих наборів, які читатимуться (повторюються) часто та змінюються рідко. (Набори для слухачів Swings - це приклад, але це насправді не безліч, і їх слід використовувати лише з EDT.)
2) Collections.synchronizedSet
просто оберне синхронізований блок навколо кожного методу вихідного набору. Ви не повинні отримувати доступ до оригінального набору безпосередньо. Це означає, що жоден два способи набору не можуть бути виконані одночасно (один буде блокувати, поки інший не закінчиться) - це безпечно для потоків, але у вас не буде сумісності, якщо кілька потоків дійсно використовують набір. Якщо ви використовуєте ітератор, вам все одно потрібно синхронізувати зовнішню сторону, щоб уникнути ConcurrentModificationExceptions при зміні набору між викликами ітератора. Виконання буде подібне до виконання оригінального набору (але з деякими синхронізацією та блокуванням при одночасному використанні).
Використовуйте це, якщо у вас лише низька конкурентоспроможність, і хочете бути впевненими, що всі зміни одразу видно в інших потоках.
3) ConcurrentSkipListSet
- це паралельна SortedSet
реалізація, що має більшість основних операцій в O (log n). Це дозволяє одночасно додавати / видаляти та читати / ітерацію, де ітерація може або не може говорити про зміни з моменту створення ітератора. Масові операції - це просто кілька одноразових викликів, а не атомно - інші потоки можуть спостерігати лише деякі з них.
Очевидно, ви можете використовувати це лише в тому випадку, якщо у вас є загальний порядок на ваших елементах. Це виглядає як ідеальний кандидат для ситуацій з високою конкурентоспроможністю, для не надто великих наборів (через O (log n)).
4) Для ConcurrentHashMap
(та набору, отриманого з нього): Тут найбільш основні варіанти (в середньому, якщо у вас хороший і швидкий hashCode()
) в O (1) (але можуть перерости до O (n)), як для HashMap / HashSet Існує обмежена паралельність запису (таблиця розділена, і доступ для запису буде синхронізований на потрібному розділі), тоді як доступ до читання повністю відповідає собі та потокам запису (але може ще не бачити результатів змін, що зараз написано). Ітератор може або не може побачити зміни з моменту його створення, а масові операції не є атомними. Змінення розміру відбувається повільно (як для HashMap / HashSet), тому спробуйте уникнути цього, оцінивши необхідний розмір при створенні (і використовуючи приблизно на 1/3 більше цього, оскільки він змінюється при заповненні 3/4).
Використовуйте це, коли у вас є великі набори, хороша (і швидка) хеш-функція, і ви можете оцінити розмір набору та необхідну одночасність перед створенням карти.
5) Чи існують інші паралельні реалізації карт, які можна використати тут?