单例(Java)

Java 中的单例与 C#非常相似,因为两种语言都是面向对象的。下面是一个单例类的示例,其中只有一个版本的对象可以在程序的生命周期内存活(假设程序在一个线程上工作)

public class SingletonExample {

    private SingletonExample() { }

    private static SingletonExample _instance;

    public static SingletonExample getInstance() {

        if (_instance == null) {
            _instance = new SingletonExample();
        }
        return _instance;
    }
}

这是该程序的线程安全版本:

public class SingletonThreadSafeExample {

    private SingletonThreadSafeExample () { }

    private static volatile SingletonThreadSafeExample _instance;

    public static SingletonThreadSafeExample getInstance() {
        if (_instance == null) {
                createInstance();
        }
        return _instance;
    }

    private static void createInstance() {
        synchronized(SingletonThreadSafeExample.class) {
            if (_instance == null) {
                _instance = new SingletonThreadSafeExample();
            }
        }
    }
}

Java 还有一个名为 ThreadLocal 的对象,它以线程为基础在线程上创建对象的单个实例。这在每个线程都需要自己的对象版本的应用程序中非常有用

public class SingletonThreadLocalExample {

    private SingletonThreadLocalExample () { }

    private static ThreadLocal<SingletonThreadLocalExample> _instance = new ThreadLocal<SingletonThreadLocalExample>();

    public static SingletonThreadLocalExample getInstance() {
        if (_instance.get() == null) {
            _instance.set(new SingletonThreadLocalExample());
        }
        return _instance.get();
    }
}

这里也是一个使用 enumSingleton 实现(只包含一个元素):

public enum SingletonEnum {
    INSTANCE;
    // fields, methods
}

任何 Enum 类实现都确保每个元素只存在一个实例。

Bill Pugh Singleton 模式

Bill Pugh Singleton Pattern 是 Singleton 类使用最广泛的方法,因为它不需要同步

public class SingletonExample {

    private SingletonExample(){}
    
    private static class SingletonHolder{
        private static final SingletonExample INSTANCE = new SingletonExample();
    }
    
    public static SingletonExample getInstance(){
        return SingletonHolder.INSTANCE;
    }
}

使用私有内部静态类,持有者不会加载到内存,直到有人调用 getInstance 方法。Bill Pugh 解决方案是线程安全的,不需要同步。

Java 文档标记下的 Singletons 主题中有更多 Java 单例示例。