【问题标题】:Singleton class with several different classloaders具有多个不同类加载器的单例类
【发布时间】:2013-03-01 11:39:17
【问题描述】:

例如,我的课程 Singleton 带有静态字段 instance

public class Singleton {

    private static Singleton instance;

    // other code, construct, getters, no matter    
}

我可以用两个不同的类加载器加载这个类两次。我怎么能避免呢?这是不安全和危险的。

另外,如果我将 instance 设置为 null,它会为两个类都设置为 null 吗?

Singleton singleton = Singleton.getInstance();
singleton = null;

【问题讨论】:

  • 如果你真的想实现单例设计模式,那么请遵循 Java 中的enum type——“单元素枚举类型是实现单例的最佳方式
  • 枚举模式不会阻止每个类加载器存在一个实例,对吗?
  • 不幸的是,枚举可能来自不同的类加载器,您可以想象这会导致各种问题。

标签: java singleton classloader


【解决方案1】:

如果您想要一个真正的Singleton 跨类加载器,那么您需要一个共同的父类来加载相关类,或者您需要自己指定类加载器。

更新:来自下面@Pshemo 的评论,下面博客中的相当一部分内容可能直接来自JavaWorld Article。我留下了博客条目,因为它可能仍然可以帮助某人,但值得知道内容最初来自哪里。

原文: 有一个blog 条目可以为您提供执行此操作的方法”(虽然我没有尝试过!),它看起来相当合理

按照下面的要求,我上面的链接中的代码 sn-p - 我建议您访问该博客以获取完整的上下文:

private static Class getClass(String classname) throws ClassNotFoundException {
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    if(classLoader == null) 
        classLoader = Singleton.class.getClassLoader();
      return (classLoader.loadClass(classname));
}

【讨论】:

  • 不错的答案!如果您在此处包含解决方案的代码示例会更好,并注明链接文章。
  • 这段代码实际上有什么帮助?如何调用它来确保单例在 ClassLoaders 中仍然是单例?
  • 还有一个非常好的网络资源可以理解这个问题。 weblogs.java.net/blog/2005/08/24/…
  • 你确定 Sneha 是那篇文章的作者(或者至少是关于类加载器的一部分)?从我看到的链接帖子发布8 JANUARY 2009,但它看起来与相当老的article from javaworld 发布Apr 25, 2003 的一部分相同。博客上的帖子甚至包含句子“可以使用前面的方法而不是Class.forName()”,这似乎与上下文无关,因为之前的任何地方都没有使用Class.forName()方法,而在javaworld中它是有意义的,因为示例 10 使用反射。
  • 这是@AnkitKumar 提供的已失效 java.net 博客 URL 的 Internet 存档 Wayback Machine 链接:web.archive.org/web/20051117213814/http://weblogs.java.net:80/…。这位作者是 Kirill Grouchnikov,标题是“你的单例实例能有多单身?”
【解决方案2】:

这是一个滥用 Properties 扩展 Map 的事实的 hack,这是一个旧的不幸的设计决策。

public final class JvmWideSingleton
{
    private static final JvmWideSingleton INSTANCE;

    static {
        // There should be just one system class loader object in the whole JVM.
        synchronized(ClassLoader.getSystemClassLoader()) {
            Properties sysProps = System.getProperties();
            // The key is a String, because the .class object would be different across classloaders.
            JvmWideSingleton singleton = (JvmWideSingleton) sysProps.get(JvmWideSingleton.class.getName());

            // Some other class loader loaded JvmWideSingleton earlier.
            if (singleton != null) {
                INSTANCE = singleton;
            }
            else {
                // Otherwise this classloader is the first one, let's create a singleton.
                // Make sure not to do any locking within this.
                INSTANCE = new JvmWideSingleton();
                System.getProperties().put(JvmWideSingleton.class.getName(), INSTANCE);
            }
        }
    }

    public static JvmWideSingleton getSingleton() {
        return INSTANCE;
    }
}

这可以被参数化,但是初始化会很懒惰并转到getSingleton()

Properties 基于Hashtable,因此它是线程安全的(根据文档)。所以可以使用props.computeIfAbsent()。但我更喜欢这种方式。

另请阅读:Scope of the Java System Properties

我刚刚写了它,有可能我忽略了一些东西会阻止它工作。

【讨论】:

  • 那里有一个错误...正在修复
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-21
相关资源
最近更新 更多