Java 线程安全的单例和内部类解决方案

Java 线程安全的单例和内部类解决方案,java,thread-safety,singleton,Java,Thread Safety,Singleton,为了在多线程应用程序中使用它,我总是这样创建线程安全的单例 public class Logger { private Logger() {} private static Logger instance = new Logger(); public static Logger getInstance() { return instance; } public void log(String s) { // Log

为了在多线程应用程序中使用它,我总是这样创建线程安全的单例

public class Logger {

    private Logger() {}

    private static Logger instance = new Logger();

    public static Logger getInstance() {
        return instance;
    }

    public void log(String s) {
        // Log here
    }
}
今天我在学习获取Java认证,在书中我发现了另一个解决方案:

public class Logger {

    private Logger() {}

    private static Logger instance;

    private static class LoggerHolder {
        public static Logger logger = new Logger();
    }

    public static Logger getInstance() {
        return LoggerHolder.logger;
    }

    public void log(String s) {
        // Log here
    }
}
他们没有提到另一个


什么更好?这两种解决方案的区别是什么?

第二个示例不太可能仅仅因为访问了类就创建实例。相反,您必须访问内部类。这种程度的偏执对JDK库设计人员来说是有意义的,但在一个更受控制的代码库中,它超出了IMHO的范围

我更喜欢简单,我会用这个来代替

public enum MyLogger {
    INSTANCE;

    public void log(String s) {
       // log here
    }
}

我强烈建议不要创建一个名为
Logger
的类,该类的许多实现已经存在足够的混乱,包括一个内置的。

第二个是懒惰的。如果,奇迹般地,程序加载了类,但从未调用
getInstance()
,那么记录器实例将不会被创建,因为它可能是一个昂贵的对象

坦白地说,如果真的需要一个单例(并且依赖注入框架几乎总是不需要),我更喜欢第一个解决方案,它更容易理解。我很少(如果有过的话)看到一个类已加载但从未在实际代码中使用的单例