Я использую WeakHashMap одновременно. Я хочу добиться мелкозернистой блокировки на основе параметра Integer; если поток A должен изменить ресурс, идентифицированный Integer a
, и поток B делает то же самое для ресурса, идентифицированного Integer b
, тогда их не нужно синхронизировать. Однако, если есть два потока, использующих один и тот же ресурс, скажем, что поток C также использует ресурс, идентифицированный Integer a
, тогда, конечно, поток A и C необходимо синхронизировать с тем же Lock.
Если больше нет потоков, которым нужен ресурс с идентификатором X, тогда блокировка на карте для ключа = X может быть удалена. Однако в этот момент может появиться другой поток и попытаться использовать блокировку в Map для ID = X, поэтому нам нужно глобальную синхронизацию при добавлении/удалении блокировки. (Это будет единственное место, где каждая нить должна синхронизироваться, независимо от параметра Integer). Но нить не может знать, когда удалить блокировку, потому что она не знает, что это последний поток, использующий блокировку.
Вот почему я использую WeakHashMap: когда идентификатор больше не используется, пару ключ-значение можно удалить, когда GC хочет его.
Чтобы убедиться, что у меня есть сильная ссылка на ключ уже существующей записи и именно эта ссылка на объект, которая формирует ключ для отображения, мне нужно выполнить итерацию keySet карты:
synchronized (mrLocks){
// ... do other stuff
for (Integer entryKey : mrLocks.keySet()) {
if (entryKey.equals(id)) {
key = entryKey;
break;
}
}
// if key==null, no thread has a strong reference to the Integer
// key, so no thread is doing work on resource with id, so we can
// add a mapping (new Integer(id) => new ReentrantLock()) here as
// we are in a synchronized block. We must keep a strong reference
// to the newly created Integer, because otherwise the id-lock mapping
// may already have been removed by the time we start using it, and
// then other threads will not use the same Lock object for this
// resource
}
Теперь, может ли содержимое Карты меняться при ее повторении? Я думаю, что нет, потому что, вызывая mrLocks.keySet()
, я создал сильную ссылку на все ключи для области итерации. Это правильно?