有 Java 编程相关的问题?

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

线程安全在Java中实现单例模式的有效方法?

Possible Duplicate:
Efficient way to implement singleton pattern in Java

我正在读这个Best Singleton Implementation In Java,但它不是线程安全的

根据维基:

if(singleton==null) { synchronized(Singleton.class) { // this is needed if two threads are waiting at the monitor at the // time when singleton was getting instantiated if(singleton==null) singleton= new Singleton(); }
}

但是查找bug实用程序在这方面给出了两个错误: 1.双重空检查。 2.静态字段的延迟初始化不正确

最好的办法是什么,

是否正确:

synchronized (Singleton.class) {
if (singleton== null) {
singleton= new Singleton();
}
}

共 (3) 个答案

  1. # 1 楼答案

    创建延迟加载单例的最有效/最简单的方法是

    enum Singleton {
       INSTANCE
    }
    

    注意:不需要锁定,因为类加载是线程安全的。默认情况下,该类是final,不能通过反射调用构造函数。在使用实例或类之前,不会创建实例。如果您担心该类可能被意外使用,可以将该单例封装在内部类中

    final class Singleton {
        private Singleton() { }
        static class SingletonHolder {
            static final Singleton INSTANCE = new Singleton();
        }
        public static Singleton getInstance() {
            return SingletonHolder.INSTANCE;
        }
    }
    
    IMPO,你必须非常偏执,认为这是一个更好的解决方案。

  2. # 2 楼答案

    对于Efficient way to implement singleton pattern in Java的接受答案中的第一个代码示例是线程安全的。创建INSTANCE由类加载器在第一次加载类时执行;它以线程安全的方式执行一次:

    public final class Foo {
    
        private static final Foo INSTANCE = new Foo();
    
        private Foo() {
            if (INSTANCE != null) {
                    throw new IllegalStateException("Already instantiated");
            }
        }
    
        public static Foo getInstance() {
            return INSTANCE;
        }
    }
    

    (抄自What is an efficient way to implement a singleton pattern in Java?

    问题中的第二个代码示例是正确的并且是线程安全的,但是它会导致对getInstance()的每次调用都进行同步,这会影响性能

  3. # 3 楼答案

    关于这个问题已经写了很多文章。是的,简单的双重检查锁定模式不安全。但是,您可以通过将静态实例声明为volatile来确保安全。新的Java内存模型规范在处理volatile时为编译器添加了一些代码重新排序限制,因此原有的风险消失了

    无论如何,我在创建实例时很少真正需要这种懒散,所以我通常只是在类加载时静态创建它:

    private static MyClass instance = new MyClass();
    

    这是简短明了的。作为替代方案,如果您真的想让它变懒,您可以利用类加载特性并执行以下操作:

    public class MyClass {
        private static class MyClassInit {
            public static final MyClass instance = new MyClass();
        }
    
        public static MyClass getInstance() {
            return MyClassInit.instance; 
        }
    ...
    }
    

    在您第一次调用getInstance()之前,不会加载嵌套类