В памяти находится большая коллекция объектов типа R . Для изменения объекта требуется блокировка записи, а для чтения - блокировка чтения. Я мог бы хранить ReadWriteLock как закрытый член класса R , однако я хочу сохранить память. В любое время только небольшой процент объектов изменяется или читается. Существуют различные способы решить не сохранять блокировку чтения-записи для конкретного ресурса (например, если он не читался или не записывался в течение некоторого времени, t ). Для целей этого вопроса предположим, что периодически можно определить, что блокировка для ресурса может быть удалена. Однако имейте в виду, что пока блокировка ресурса удаляется в потоке, один или несколько других потоков могут попытаться изменить или прочитать ресурс. Все это происходит в многопоточной среде. Как бы вы реализовали это с наименьшим количеством блокировок?
Например, один из способов сделать это - сохранить блокировки чтения-записи в параллельной карте:
Map<R,ReadWriteLock> map = new ConcurrentHashMap<>();
Когда определено, что блокировку чтения-записи для ресурса можно удалить, удалите его с карты. Однако, как упомянуто выше, возможно, что после того, как было решено удалить запись и до того, как запись будет удалена, другие потоки могут захотеть получить блокировку чтения или записи.
Вы можете подумать, что можно использовать комбинацию computeifabsent и remove . Однако это не работает. Например:
//--Thread1 write lock--
ReadWriteLock rwl = map.computeIfAbsent(r, r -> new ReadWriteLock()); // 1
rwl.writeLock.lock(); // 4
//Modify r here
//--Thread2: Removing entry--
map.remove(r); // 2
//Thread3: write lock
ReadWriteLock rwl = map.computeIfAbsent(r, r-> new ReadWriteLock()); // 3
rwl.writeLock.lock(); // 5
//Modify r here.
Проблема заключается в том, что объект блокировки потоком 1 не будет совпадать с блокировкой, полученной потоком 3, и неправильно разрешать две записи одновременно. Цифры справа показывают порядок исполнения.
В ответе не обязательно использовать параллельную карту, как показано в примере выше, но, похоже, это хорошее начало и обеспечивает одновременный доступ к блокировкам. Если вы используете параллельную карту, не стесняйтесь оборачивать ReadWriteLock в другую структуру или создавать собственную версию ReadWriteLock.
В итоге вопрос заключается в том, как сохранить блокировки чтения-записи для коллекции ресурсов без необходимости сохранять блокировку чтения-записи для каждого объекта в коллекции и минимизировать конфликт блокировки.