Двойное сопоставление с HashMap

Мы работали над куском кода для получения синглтонов. Мы пытаемся получить их, если класс существует в нашей коллекции, мы возвращаем его, в противном случае мы создаем его и сохраняем в нашей коллекции. Мы используем двойную проверку блокировки, чтобы убедиться, что мы не синхронизируемся при каждой операции get.

Однако в соответствии со многими статьями двойная проверка блокировки сломана. Однако я не знаю, так ли это на самом деле, так как карта уже инициализирована и проверка выполняется на ее содержимом. Что, вы парни, думаете? в любом случае, чтобы здесь работал двойной контроль блокировки?

Map <Class <?>, Object> clazzes = getClazzes ();
T singleton = null;
if (false == clazzes.containsKey (clazz))
{
     synchronized (clazzes)
     {
         if (false == clazzes.containsKey (clazz))
         {
            try
            {
                singleton = clazz.newInstance ();
                clazzes.put (clazz, singleton);
            }
            catch (InstantiationException e)
            {
                 throw new IllegalArgumentException ( "cannot instantiate class " + clazz, e);
            }
            catch (IllegalAccessException e)
            {
                  throw new IllegalArgumentException ("cannot instantiate class " +  clazz, e);
            }
         }
         else
         {
             singleton = clazz.cast (clazzes.get (clazz));
         }
      }
 }

Спасибо

2 ответа

Решение

Итак, я провел небольшое исследование. Согласно этому документу операция put имеет отношение "происходит до" с ключами. Следовательно, если мы используем ConcurrentHashMap, двойная проверка блокировки должна работать

Не мешать горшок без необходимости, но есть хорошие реализации этого шаблона - что-то вроде https://code.google.com/p/guava-libraries/wiki/CachesExplained

// Construction/setup
LoadingCache<Class<?>, Object> singletons = CacheBuilder.newBuilder()
       .build(
           new CacheLoader<Class<?>, Object>() {
             public Object load(Class<?> key) throws AnyException {
               return key.newInstance();
             }
           });
// client threads
return singletons.get(String.class);

Большим преимуществом этого класса по сравнению с вашей реализацией является то, что вызывающие абоненты блокируют ключ, а не карту. Таким образом, два потока, получающие два отдельных синглета, могут продолжаться. Два потока, получающие один и тот же синглтон, будут ждать его создания.

Другие вопросы по тегам