0

我们一直在编写一段代码来获取单例。我们尝试获取它们,如果该类存在于我们的集合中,我们将返回它,否则我们创建它并将其存储在我们的集合中。我们使用双重检查锁定来确保我们不会在每个 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));
         }
      }
 }

谢谢

4

2 回答 2

0

好的,所以我做了一些研究。根据此文档,put 操作与包含键具有发生前的关系。因此,如果我们使用 ConcurrentHashMap 双重检查锁定应该可以工作

于 2014-04-28T10:39:53.817 回答
0

不要不必要地搅动锅,但是这种模式有很好的实现——比如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);

与您的实现相比,此类的最大优势在于调用者按键而不是按映射阻塞。因此,获得两个单独的单例的两个线程都可以继续进行。获得相同单例的两个线程将等待它被构造。

于 2014-05-07T05:39:46.560 回答