2016-06-14 3 views
1

Моя цель - синхронизировать доступ к нескольким() объектам, внешним по отношению к программе. ReentrantReadWriteLock представляет собой хорошую модель для управления объектом только. Однако в моем случае было бы безумным создание объекта RWL для каждого синхронизированного объекта. К счастью, менее сто из них будут доступны в тот же момент.Dynamic ReentrantReadWriteLock-s для синхронизации доступа к большому количеству объектов

Таким образом, я решил создать сервис, который предоставляет интерфейс, как это:

void acquireReadLock(String id) { 
    rwl = ....... // get or create RWL object 
    rwl.writeLock().lock(); 
} 

void acquireWriteLock(String id) { 
} 

void releaseReadLock(String id) { 
} 

void releaseWriteLock(String id) { 
} 

Внедрение методов «захватит» использует простой ленивый инициализацию instaniate объект RWL для элемента, или получить его из кэша. Однако методы «выпуска» должны включать дополнительную логику, которая проверяет, требуется ли RWL (= не имеет блокировок). Если нет, я могу безопасно удалить RWL из кеша, иначе память скоро будет залита ими.

Чтобы реализовать эту логику очистки, мне нужен способ выполнить соответствующие проверки. Методы «getReadLockCount()» и «isWriteLocked()» кажутся подходящими кандидатами, но это qoute от JavaDoc меня беспокоит много:

Этот метод предназначен для использования в состоянии системы мониторинга, а не для контроля синхронизации.

Итак, безопасно ли использовать их для выполнения моей задачи? Возможно ли другое решение?

+1

Вы уверены, что создание тысяч 'ReentrantReadWriteLock' создает проблему?ИМХО вы должны иметь возможность создавать миллионы из них без негативного воздействия на JVM –

+0

Тысячи - это типичное количество. В конечном итоге сумма в основном не ограничена, но RAM нет, даже если JVM может обрабатывать их все одновременно. –

+0

Что делать, если я пытаюсь выполнить tryLock()? Если это удастся, это означает, что никто не имеет блокировки любого типа. Затем я могу безопасно удалить RWL из списка. На данный момент я не вижу никаких побочных эффектов. –

ответ

1

Использование только getReadLockCount() и isWriteLocked() не будет безопасно для вашей задачи, так как блокировка может быть бесплатной, когда освобождающий поток называется функциями, но другой поток может получить или начать ждать блокировки до освобождения поток удалил блокировку из кеша. Последнее возражение - то, что другой поток может начать ждать блокировки, также применяется к tryLock().

Одним из способов обращения с этим было бы использование простого объекта в качестве защитного замка, который необходимо будет синхронизировать с помощью любого потока при блокировке или разблокировке блокировки чтения/записи. Когда задача завершится, она заблокирует блокировку защиты, а затем, если блокировка чтения/записи будет полностью бесплатной, удалите блокировку чтения/записи, а затем удалите блокировку защиты. К тому моменту могут быть другие потоки, ожидающие блокировки блокировки, но как только они их приобретут, они увидели бы, что больше нет доступной блокировки чтения/записи, и они возвращаются и создают новую защиту и блокировку чтения/записи.

Процесс создания замков должны быть синхронизированы в некотором роде - либо глобально с использованием synchronized блока или функции, или, возможно, с помощью ConcurrentHashMap и его метод putIfAbsent() - чтобы избежать условий гонки между двумя нитями пытаются создать замки на в то же время. Поток должен блокировать блокировку блокировки перед тем, как попытаться поместить его, и новый замок чтения/записи в кеш, и если он получил другую блокировку защиты от putIfAbsent(), отмените создание новой блокировки и подождите от возвращаемого объекта.

Лично, потому что этот подход немного сложный и может привести к скрытым условиям гонки, если он не написан отлично, я бы рассмотрел возможность просто блокировать чтение и запись для всех внешних объектов. Не должно быть никаких проблем с миллионами внешних объектов, по крайней мере, и десятками или сотнями миллионов, если у вас есть несколько гигабайт памяти, доступных для вашего процесса.

+0

Спасибо за подробный ответ! Я собирался использовать синхронизированный блок для доступа к кешу, просто не упомянул об этом, потому что он совершенно очевиден. Что касается состояния гонки, я не думаю, что это может серьезно повлиять на производительность, поскольку внешние объекты на самом деле являются файлами с типичным размером в десятки или даже мегабайтами hundrends. Таким образом, передающий защитный блок ОЧЕНЬ маловероятен, приведет к тому, что нить будет достаточно долго голодать. Это o (время), учитывающее передачу данных. –

+0

Что для очистки кеша, я верю Я могу использовать HashMap со слабыми значениями. –

Смежные вопросы