Синхронизация группы объектов

113
23 августа 2019, 04:00

Доброго времени суток.

С чем имеем дело:

Есть список объектов(ArrayList). К объектам списка очень часто (60 и более раз в секунду) обращаются несколько потоков. Каждый поток обращаясь к объекту выполняет над ним операцию которая может занять очень много времени. Необходимо синхронизировать работу потоков с этой коллекцией.

Как я пытался решить задачу:

  1. самое первое решение: делать синхронизацию на уровне самой коллекции, т.е. пока один поток работает с коллекцией - другие ждут его. Но у каждого из потоков есть операции над объектом, которые могут занять очень много времени(несколько секунд), и как итог, программа стала сильно виснуть.
  2. Далее я заметил - некоторые из потоков никогда не обращаются ко всем объектам коллекции сразу, а обращаются к небольшой группе(состав и размер группы объектов, с которыми может работать потоком все время меняется.). Решил делать синхронизацию на уровне каждого отдельного объекта, т.е. пока поток 1 занимается одним объектом, другим потокам ничего не мешает заниматься другими. Но тут появились сложности связанные с необходимостью работы с группой объектов как с одним целым.

Вопрос:

Предположим есть группа из 4 объектов (A, B, C, D). Поток 1 синхронизируется на этой группе и пока он занят работой с объектом A, другие потоки не могут получить доступ не только к объекту A, но и к объектам B, C и D. При этом - пытаясь получить доступ, скажем к объекту B, другой поток будет заблокирован(как при попытке захватить занятый монитор) до тех пор, пока поток работающий с группой не закончит работу СО ВСЕМИ объектами из группы. Как это реализовать?

Answer 1

На данный момент, воспользовавшись советом выше, я нашел решение с помощью Reentrantlock. Решение следующие - каждый критический метод синхронизируется с помощью ReetrantLock(также, как мы бы это делали с помощью synchronized). Далее создаем ещё два метода - lock() и unlock() которые делегируют вызов соответствующим методам ReentrantLock. Когда поток собирается работать с группой объектов, он предварительно вызывает lock() у каждого объекта, далее работает с ними, а после завершения работы вызывает unlock() у каждого объекта. Мне не нравится это решение, поскольку можно легко выстрелить себе в ногу, но оно рабочее, простое в реализации и должно быть быстрее вариантов с wait(). А чтобы не было deathlock необходимо захватывать объекты всегда в одном и том же порядке(как написали выше в коментариях).

Answer 2

Вам нужна не synchronized collection, а concurrent collection, то есть блокировка не всей коллекции при работе с ним, а конкретного элемента коллекции.

Таковым является CopyOnWriteArrayList

Существенным минусом данной реализации является то что при операции вставки/удаления будет производиться полная копия списка (поэтому он так и называется CopyOnWriteArrayList), если у вас операции удаления/добавления в список редкие, то это рабочий вариант.

Если не подходит, то надо пересмотреть коллекцию на что-то другое, например ConcurrentLinkedQueue

READ ALSO
Как работает Get Active Element

Как работает Get Active Element

В appium документации есть Get Active Element

99
Получить данные из localStorage

Получить данные из localStorage

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

125
Курсор мыши фонового режима (JavaFX)

Курсор мыши фонового режима (JavaFX)

Существуют различные типы курсоров мыши: https://ruwikipedia

108
захват границ в регулярных выражениях Java

захват границ в регулярных выражениях Java

Есть задание, вырезать предложения из текстаЯ использовал метод

84