Вибір найкращого списку одночасності на Java [закритий]


98

Мій пул потоків має фіксовану кількість потоків. Ці теми потрібно часто писати та читати зі спільного списку.

Отже, яка структура даних (краще це Список, має бути без моніторингу) в java.util.concurrentпакеті найкраща в цьому випадку?


5
Це залежить від того, що ви хочете зробити з колекцією. Дивіться мій пост у блозі (хоча мова йде про .Net, поняття однакові). Ви навряд чи зможете написати правильний код, захищений від потоку, з використанням List.
Слакс

1
Зараз я використовую CopyOnWriteArrayList , але виняток ConcurrentModificationException все ще періодично кидається.
象 嘉 道

2
Будь ласка, додайте більше інформації про те, що ви робите зі збіркою, щоб люди могли краще відповісти, інакше це лише здогадка.
маттш

2
Можливо, ConcurrentModificationExceptionце не є проблемою синхронізації; вона також виникає, наприклад, у циклі for для циклу колекції, де ви намагаєтесь видалити елемент із колекції.
toto2

1
Я знаю, що це не частина пакету, але хтось спробував Vector?
WesternGun

Відповіді:


96

краще було б List

Тільки List впровадження в java.util.concurrentцьому CopyOnWriteArrayList . Існує також можливість синхронізованого списку, як згадує Тревіс Вебб.

Однак ви впевнені, що вам це потрібно List? Існує набагато більше варіантів для одночасних Queues і Maps (і ви можете зробити Sets з Maps), і ці структури, як правило, мають найбільш сенс для багатьох типів речей, які ви хочете зробити зі спільною структурою даних.

Для черг у вас є величезна кількість варіантів, і що є найбільш підходящим, залежить від того, як вам потрібно його використовувати:


14
CopyOnWriteArrayListНедоліком є ​​те, що він дуже дорогий при написанні (але дешевий для читання) Якщо ви робите багато записів, вам краще синхронізувати список або чергу.
Пітер Лорі

67

Будь-яку колекцію Java можна зробити безпечною для потоків так:

List newList = Collections.synchronizedList(oldList);

Або щоб створити абсолютно новий безпечний для потоку список:

List newList = Collections.synchronizedList(new ArrayList());

http://download.oracle.com/javase/6/docs/api/java/util/Collections.html#synchronizedList(java.util.List)


7
З цієї причини у java.util.concurrent - Uhm , ви не знайдете жодних реалізацій списку - є ConcurrentHashMapнавіть те, що існує Collections.synchronizedMapметод.
aioobe

7
Прочитайте Javadocs на ConcurrentHashMap. Деталі реалізації синхронізації різні. використовуючи synchronizedметоди в Collectionsосновному просто загортає клас в монітор Java. ConcurrentHashMapвикористовує більш розумні функції одночасності.
Travis Webb

1
Так. Тим не менш, це робить ваше останнє речення таким чином недійсним.
aioobe

1
Якщо ви використовуєте монітор, продуктивність програми дійсно погана :-(
象 嘉 道

5
Додамо лише, що ітерація над newList не є безпечною для потоків. !!
bluelurker

9

Якщо розмір списку, якщо він фіксований, ви можете використовувати AtomicReferenceArray . Це дозволить вам проіндексувати оновлення слота. Ви можете написати перегляд списку, якщо потрібно.


6

Ви можете поглянути на ConcurrentDoublyLinkedList, написаний Дугом Лі на основі списку Пола Мартіна "Практичний список з двома пов'язаними з замком". Він не реалізує інтерфейс java.util.List, але пропонує більшість методів, які ви використовуєте у списку.

За заявою javadoc:

Одночасна реалізація Deque (дворядна черга). Одночасні операції з вставки, видалення та доступу виконуються безпечно в декількох потоках. Ітератори слабо узгоджуються , повертаючи елементи, що відображають стан деке в певний момент у або після створення ітератора. Вони не кидають ConcurrentModificationException, і можуть продовжувати паралельно з іншими операціями.


5

ConcurrentLinkedQueueвикористовує чергу без замків (на основі новіших інструкцій CAS ).


7
... який не реалізує Listінтерфейс.
aioobe

1
eSniff, як би ти реалізував List.set(int index, Object element)ConcurrentLinkedQueue?
Джон Вінт

4
Більшість Listметодів -specific або не буде реалізовуватись за допомогою Queue(наприклад, додавання / встановлення за певним індексом), або можуть бути реалізовані, але будуть неефективними (отримати з індексу). Тому я не думаю, що ви могли б насправді обернути це. Тим не менш, я вважаю, що пропозиція щодо Queueштрафу є чудовою, оскільки ОП насправді не пояснив, чому вони потрібні List.
ColinD

1
@ColinD - це та відповідь, на яку я йшов. Існують вагомі причини, чому CLQ не можна обернути у список. Хоча я згоден, не можу виключити інтерфейс черги.
Джон Вінт,

1
❗️ Варто зазначити, що: "Остерігайтеся, що, на відміну від більшості колекцій, метод розміру НЕ є операцією постійного часу. Через асинхронність цих черг визначення поточної кількості елементів вимагає обходу елементів".
Бехранг Саедзаде

3

Якщо встановленого рівня достатньо, може бути використаний ConcurrentSkipListSet . (Його реалізація базується на ConcurrentSkipListMap, який реалізує список пропусків .)

Очікувана середня вартість часу - це журнал (n) для операцій, що містять, додають та видаляють; метод розміру не є операцією постійного часу.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.