2015-04-16 2 views
1

У меня есть ситуация, когда вызывающие абоненты хотели бы получить объект из компонента в зависимости от текущего экземпляра (идентификатора). Теперь, если объект текущего компонента существует для текущего экземпляра, он не должен быть создан снова. Таким образом, есть два пути (я думаю), это может быть сделано -Который должен использоваться - ConcurrentHashMap putIfAbsent или блокировка карты

1. Using putIfAbsent of ConcurrentHashMap 

beanObject = objectFactory.get(); // this will create new instance every time 
// even if not required 
beanObject = beanMapForInstance.putIfAbsent(name, beanObject); 
return beanObject; 

Или

2. By Locking the map 

beanObject = beanMapForInstance.get(name); // beanMapForInstance is a ConcurrentHashMap 
if(beanObject == null){ 
    synchronized (beanMapForInstance) { 
     beanObject = beanMapForInstance.get(name); 
     if(beanObject == null){ 
      beanObject = objectFactory.getObject(); 
      beanMapForInstance.put(name, beanObject); 
     } 
    } 
} 
return beanObject; 

В первый метод создается новый объект каждый раз, так что я думаю, что второй должен быть предпочтительным. Но findbugs показывает проблему для второго варианта синхронизации, выполняемой на ConcurrentHashMap, и какой из них следует использовать?

ответ

1

В вашем случае нет выбора: вы не можете заблокировать ConcurrentHashMap. Точнее, блокировка ConcurrentHashMap не работает так, как вы ожидали. Это не делает ваше действие безопасным для потока, так как операции по обеспечению безопасности потока в ConcurrentHashMap не достигаются путем синхронизации самого объекта.

Цитируется Javadoc of ConcurrentHashMap:

Этот класс полностью совместим с Hashtable в программах, которые полагаются на его безопасности потока, а не на деталях синхронизации

Если вы не хотите, чтобы ненужные создать значение, то вы можете использовать computeIfAbsent, если вы используете JDK 8+, который вы можете отложить создание, пока оно действительно не понадобится.

+0

Ну, блокировка не повлияет на какой-либо другой код, но выше pattern2 будет работать до тех пор, пока никто другой не имеет доступа к карте (который предположительно является закрытым для этого класса менеджера компонентов). Объект блокировки также может быть полностью несвязанным объектом блокировки (не обязательно должна быть сама карта). На самом деле, это, вероятно, предпочтительнее для ясности. – Thilo

+0

'computeIfAbsent' приятно. – Thilo

+0

Если кто-то еще не использует ConcurrentHashMap, зачем его использовать? Просто используйте блокировку HashMap, которая даст такую ​​же, если не лучшую производительность, как синхронизацию ConcurrentHashMap. –

0

Как насчет проверки на наличие первого и только тогда putIfAbsent?

beanObject = beanMapForInstance.get(name); 
if (beanObject == null){ 
    beanObject = beanMapForInstance.putIfAbsent(
     name, objectFactory.get()); 
} 

будет работать 99,99% время, а в очень редких гонки условиях случае, вы вызываете избыточный конструктор (который, по-видимому, не является проблемой для вас соображений производительности за исключением).

+0

Спасибо за решение. Исправьте меня, если я ошибаюсь, ваш код делает то же самое, что и второе решение, отправленное мной, но делает это внутри? –

+1

Ну, это позволяет избежать синхронизированного блока. Предположительно ConcurrentHashMap либо полностью блокирован, либо делает его более эффективным, по крайней мере. – Thilo

+0

@SachinGorade Я думаю, вы пропустили суть: этот подход не может избежать всех случаев создания ценности без необходимости. Однако это достаточно хорошо в реальной ситуации, если вам не нужно полностью избегать избыточного создания боба. –

Смежные вопросы