Я сосу на формулировку вопросов. У меня есть следующий фрагмент кода (Java) (псевдо):
public SomeObject getObject(Identifier someIdentifier) {
// getUniqueIdentifier retrieves a singleton instance of the identifier object,
// to prevent two Identifiers that are equals() but not == (reference equals) in the system.
Identifier singletonInstance = getUniqueIdentifier(someIdentifier);
synchronized (singletonInstance) {
SomeObject cached = cache.get(singletonInstance);
if (cached != null) {
return cached;
} else {
SomeObject newInstance = createSomeObject(singletonInstance);
cache.put(singletonInstance, newInstance);
return newInstance;
}
}
}
По сути, он делает идентификатор «уникальным» (ссылка равна, как в ==
), проверяет кеш, а в случае его отсутствия вызывает дорогой метод (включая вызов внешнего ресурса, анализ и т. Д.) , помещает это в кеш и возвращает. Синхронизированный Identifier
в этом случае избегает использования двух equals()
, но не ==
Identifier
объектов, используемых для вызова дорогостоящего метода, который бы одновременно получал один и тот же ресурс.
Выше работает. Мне просто интересно, и, возможно, микрооптимизация, будет ли перезапись, такая как следующая, которая использует более наивное извлечение кеша и двойную проверку блокировки, быть «безопасной» (безопасной, как в поточно-безопасной, без лишних условий гонки) и быть «более оптимальный '(как в сокращении ненужных блокировок и потоков, ожидающих блокировки)?
public SomeObject getObject(Identifier someIdentifier) {
// just check the cache, reference equality is not relevant just yet.
SomeObject cached = cache.get(someIdentifier);
if (cached != null) {
return cached;
}
Identifier singletonInstance = getUniqueIdentifier(someIdentifier);
synchronized (singletonInstance) {
// re-check the cache here, in case of a context switch in between the
// cache check and the opening of the synchronized block.
SomeObject cached = cache.get(singletonInstance);
if (cached != null) {
return cached;
} else {
SomeObject newInstance = createSomeObject(singletonInstance);
cache.put(singletonInstance, newInstance);
return newInstance;
}
}
}
Вы можете сказать «Просто протестируйте это» или «Просто сделайте микропроцессор», но тестирование многопоточных фрагментов кода не является моей сильной стороной, и я сомневаюсь, что смогу смоделировать реалистичные ситуации или точно фальшивые условия гонки. Кроме того, это заняло бы у меня полдня, в то время как написание ТАКОГО вопроса у меня заняло всего несколько минут:).