MySQL имеет удобную функцию:
SELECT GET_LOCK("SomeName")
Это можно использовать для создания простых, но очень специфических, основанных на имени блокировок для приложения. Однако для этого требуется подключение к базе данных.
У меня много ситуаций вроде:
someMethod() {
// do stuff to user A for their data for feature X
}
Нет смысла просто синхронизировать этот метод, потому что, например, если этот метод вызывается для пользователя B тем временем, пользователю B не нужно ждать, пока пользователь A закончит до его запуска, будут выполняться только операции для пользователя A и комбинации элементов X нужно ждать.
С блокировкой MySql я мог бы сделать что-то вроде:
someMethod() {
executeQuery("SELECT GET_LOCK('userA-featureX')")
// only locked for user A for their data for feature X
executeQuery("SELECT RELEASE_LOCK('userA-featureX')")
}
Поскольку блокировка Java основана на объектах, мне кажется, что мне нужно будет создать новый объект, чтобы представить ситуацию для этой блокировки, а затем помещать его в статический кеш где-то, чтобы все потоки могли его видеть. Последующие запросы блокировки для этой ситуации затем найдут объект блокировки в кеше и приобретут его блокировку. Я попытался создать что-то вроде этого, но тогда для кэша блокировки нужна синхронизация. Кроме того, трудно обнаружить, когда объект блокировки больше не используется, чтобы его можно было удалить из кеша.
Я просмотрел параллельные пакеты Java, но ничто не отличается тем, что можно обрабатывать что-то вроде этого. Есть ли простой способ реализовать это, или я смотрю на это с неправильной точки зрения?
Edit:
Чтобы уточнить, я не хочу заранее создавать предопределенный пул блокировок, я бы хотел создать их по требованию. Некоторый псевдокод для того, что я думаю:
LockManager.acquireLock(String name) {
Lock lock;
synchronized (map) {
lock = map.get(name);
// doesn't exist yet - create and store
if(lock == null) {
lock = new Lock();
map.put(name, lock);
}
}
lock.lock();
}
LockManager.releaseLock(String name) {
// unlock
// if this was the last hold on the lock, remove it from the cache
}