Я пытаюсь реализовать класс обработчика ресурсов, который назначает ресурсы (строки, хранящиеся в массиве) нескольким клиентам, которые могут попытаться получить блокировку на множестве ресурсов и разблокировать их с помощью идентификатора методом блокировки.Менеджер ресурсов с ReentrantLocks
Я пытаюсь использовать справедливые ReentrantReadWriteLock-s, по одному для каждого ресурса.
Я вижу только журнал клиента.
Существует несколько проблем, иногда поток не прекращает запрашивать и приобретать ресурсы, иногда происходит взаимоблокировка, а иногда и сбой releaseLock. Любые советы оценены.
public class ResHandler {
//ID-s of the granted resource lists
private static long lockNum = 0;
//Resources are identified by strings, each client has a list of demanded resources
//we store these when granted, along with an ID
private static ConcurrentHashMap<Long, Set<String>> usedResources
= new ConcurrentHashMap<Long, Set<String>>();
//We store a lock for each resource
private static ConcurrentHashMap<String, ReentrantReadWriteLock> resources
= new ConcurrentHashMap<String, ReentrantReadWriteLock>();
//Filling our resources map with the resources and their locks
static {
for (int i = 0; i < SharedValues.RESOURCE_LIST.length; ++i) {
String res = SharedValues.RESOURCE_LIST[i];
//Fair reentrant lock
ReentrantReadWriteLock lc = new ReentrantReadWriteLock(true);
resources.put(res, lc);
}
}
//We get a set of the required resources and the type of lock we have to use
public static long getLock(Set<String> mNeededRes, boolean mMethod) {
//!!!
if (mMethod == SharedValues.READ_METHOD) {
//We try to get the required resources
for (String mn : mNeededRes)
resources.get(mn).readLock().lock();
//After grandted, we put them in the usedResources map
++lockNum;
usedResources.put(lockNum, mNeededRes);
return lockNum;
}
//Same thing, but with write locks
else {
for (String mn : mNeededRes)
resources.get(mn).writeLock().lock();
++lockNum;
usedResources.put(lockNum, mNeededRes);
return lockNum;
}
}
//Releasing a set of locks by the set's ID
public static void releaseLock(long mLockID) {
if (!usedResources.containsKey(mLockID)) {
System.out.println("returned, no such key as: " + mLockID);
return;
}
Set<String> toBeReleased = usedResources.get(mLockID);
//Unlocking every lock from this set
for (String s : toBeReleased) {
if (resources.get(s).isWriteLockedByCurrentThread())
resources.get(s).writeLock().unlock();
else
resources.get(s).readLock().unlock();
}
//Deleting from the map
usedResources.remove(mLockID);
}
}
Там одна вещь, которая меня озадачивает: Строки неизменны в Java. Другими словами, блокировка или отсутствие блокировки, вы все равно не можете писать в строку! Но в любом случае давайте предположим, что они просто используются в качестве примеров. В этом случае важно, чтобы все блокировки были приобретены в том же порядке, чтобы избежать взаимоблокировок, убедитесь, что Set <> гарантирует это. Затем вы можете сохранить не только идентификатор блокировки, но и идентификатор потока, которому они принадлежат. Таким образом, вы можете убедиться, что поток не выпускает ничего, что он не владеет, и что поток не блокируется снова, прежде чем отпускать, что может привести к блокировке из-за заказа снова. –
Строки не изменяются, они представляют только ресурсы, клиенты просто ждут от них. Я пробовал ваши предложения, а вместо Sets я использовал Vector для хранения пар данных resourceName и lock, а другой Vector - для хранения распределений, поэтому блокировки приобретаются в том же порядке. При освобождении я также проверяю поток. Я также сделал lockNum изменчивым. Проблемы все еще сохраняются. – user1875619
Я не думаю, что использование вектора помогает, потому что этот, безусловно, не отсортирован. Хуже того, я верю в набор, у вас есть гарантия, что дубликатов нет, а в векторе вы этого не делаете. Тем не менее, в коде есть условие гонки с 'lockNum': вы увеличиваете его, второй поток увеличивает его, и оба используют одно и то же значение. 'volatile' там не помогает, возможно, синхронизация функции будет. BTW: использование одного замка для управления всеми ресурсами позволит решить вашу проблему, хотя вам придется реализовать несколько функций мелкозернистой блокировки. –