有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

多线程是Java threadsafe(和GCsafe)中的弱单例实现吗?

我希望取得以下成果:

  • 我希望这个类的实例不超过一个。当类有多个引用时,我希望它们都引用同一个实例
  • 除非有必要,否则我不想让实例出现。具体来说,我希望垃圾收集器能够在不使用时回收实例,并在下次请求实例时重新创建它
  • 多个线程可能会请求一个实例,因此操作必须是线程安全的

这是我想出的代码:

public final class MyClass {
    private static WeakReference<MyClass> instance;
    public static synchronized MyClass getInstance() {
        if ((instance == null) || (instance.get() == null)) {
            instance = new WeakReference<MyClass>(new MyClass());
        }
        // TODO what if GC strikes here?
        return instance.get();
    }
}

设计选择包括:

  • 延迟初始化,因此除非需要,否则不会创建实例
  • 该类保留对实例的WeakReference,以便在不再使用该实例时可以对其进行垃圾收集
  • getInstance()方法是synchronized(to MyClass),因此一次只能由一个线程执行

问题:

  • 这个设计会像我预期的那样运行并产生预期的结果吗
  • 我是否需要担心getInstance()被注释所在的垃圾收集器打断(这意味着垃圾收集器将回收我正要返回的实例)?如果是的话,我该如何应对

共 (1) 个答案

  1. # 1 楼答案

    在变量中保存MyClass的本地副本,而不是只将引用的唯一副本提供给WeakRefrence的构造函数。这将防止GC在new WeakReference<MyClass>调用和函数返回之间收集instance

    public final class MyClass {
        private static WeakReference<MyClass> instance;
        public static synchronized MyClass getInstance() {
            MyClass classInstance = null;
            if (instance != null) {
                classInstance = instance.get();
                if(classInstance != null)
                {
                    return classInstance;
                }
            }
    
            classInstance = new MyClass();
            instance = new WeakReference<MyClass>(classInstance);
    
            //This is now a strong reference and can't be GC'ed between the previous line and this one.
            return classInstance;
        }
    }