Другое решение, на которое я наткнулся, размышляя об этом: один из способов рассмотрения проблемы состоит в том, что она вызвана повторным входом замков. ReentrantReadWriteLock
отслеживает владение замком для обработки повторного входа. Если я хочу получить блокировки при создании потока и снять блокировки при закрытии потока, а также закрыть потоки в потоках, отличных от тех, в которых они были созданы, то блокировка с повторным входом не будет работать, поскольку неправильный поток будет владеть блокировкой потока.
Одним из способов решения этой проблемы является использование счетной блокировки, но принудительная установка всей блокировки наружу. Во-первых, блокировка подсчета: Состояния являются целыми числами -1,0,1, ...., где -1 означает запись, 0 означает разблокировку, а положительные n подсчитывают количество одновременных операций чтения. Таким образом, записи по-прежнему являются эксклюзивными, но блокировки не зависят от потока. Вынуждение всех блокировок наружу: у нас есть методы типа exists()
, где нам нужно получить блокировку чтения, но exists()
вызывается некоторыми методами, которые уже имеют блокировку записи. Итак, мы разбили кишки exists()
на защищенные existsImpl()
, которые следует вызывать только тогда, когда блокировка уже удерживается (то есть внутренне, другими методами *Impl()
. Таким образом, после получения блокировки Вызываются только разблокирующие методы Impl, и мы избегаем необходимости повторного входа.
Это все хорошо, за исключением того, что в конечном итоге он становится чрезвычайно сложным, чтобы гарантировать, что вы не облажаетесь при его реализации - вызывая открытый заблокированный метод, когда вы должны вызывать защищенный незафиксированный - - и тем самым создавая тупик. Во-вторых, навязывание всех ваших замков наружу означает, что вы дольше удерживаете эти замки, так что это (вероятно) не подходит для параллелизма.
Итак, я попробовал это, но решил не использовать.