Как мне управлять управлением записями в карте объектов блокировки? - PullRequest
0 голосов
/ 16 мая 2019

Мое приложение создает индекс, который сохраняется в тысячах файлов на диске.Я хочу получить доступ к индексным файлам с несколькими экземплярами приложения.Поэтому я использую java FileLock для блокировки файлов, которые я читаю, между различными JVM.
Если я пытаюсь получить FileLock дважды с одним и тем же приложением, я получаю OverlappingFileLockException (именно так FileLock должен работать),Чтобы предотвратить многократное приобретение одного и того же файла в одном экземпляре, я создаю карту.Если приложение может получить семафор для определенного файла, оно также может получить FileLock.Если нет, файл в данный момент используется приложением.С ConcurrentHashMap он работает как шарм.Я использую computeIfAbsent, чтобы добавить Семафоры на карту, если это необходимо.

Проблема в том, что чем больше файлов я создаю, тем больше семафоров я сохраняю на карте.Запуск приложения в течение нескольких дней может привести к взрыву карты.Чтобы предотвратить это, я хочу удалить неиспользуемые записи, когда они будут освобождены.

Я не могу просто удалить семафор, как во 2-й версии функции.Если семафор поставил потоки в очередь, следующий поток в очереди получит FileLock.Новый поток не найдет семафор на карте и создаст новый, снова получая FileLock.Я должен проверить, если semaphore.hasQueuedThreads() и удалить его, только если нет очереди потока.Но это не атомная операция.Я попытался заблокировать функции получения / выпуска для семафора с помощью одного семафора, чтобы синхронизировать обе функции (плохая практика), просто чтобы посмотреть, может ли он работать.Это закончилось тупиком.

val lockMap = ConcurrentHashMap<String, Semaphore>()

fun accessFile(fileName: String) {
    acquireSemaphore(fileName: String)
    acquireFileLock(fileName: String)
    doSomethingWithFile(fileName: String)
    releaseFileLock(fileName: String)
    releaseSemaphore(fileName: String)
}

fun acquireSemaphore(fileName: String) {
    (lockMap.computeIfAbsent(fileName){Semaphore(1, true)}).acquire()
}

fun releaseSemaphore(fileName: String) {
    lockMap[fileName]?.release()                // works, but the map keeps every semaphore
}

fun releaseSemaphore(fileName: String) {
    lockMap.remove(filename)?.release()     // removes the semaphore, but causes OverlappingFileLockExceptions
}

Я хочу удалить семафор с карты, когда он выпущен, и нет потоков, ожидающих семафор.Это должна быть атомарная операция, поэтому второй семафор для этого файла не создается.

...