Java单例模式面试题

引言

在Java开发中,单例模式是一种常见的设计模式。它用于确保一个类只有一个实例,并且提供了全局访问该实例的方式。在面试过程中,面试官经常会问一些关于单例模式的问题,以评估面试者对设计模式的理解和应用能力。本文将介绍几个常见的单例模式面试题,并提供相应的代码示例。

问题1:如何实现懒汉式单例?

懒汉式单例是指在第一次调用获取实例的方法时才创建实例。以下代码示例展示了一种懒汉式单例的实现方式:

public class LazySingleton {
    private static LazySingleton instance;

    private LazySingleton() {
        // 私有构造方法,防止外部创建实例
    }

    public static synchronized LazySingleton getInstance() {
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }
}

在上述代码中,instance变量是私有的,并且通过getInstance()方法进行获取。在第一次调用getInstance()方法时,会创建一个LazySingleton实例并赋值给instance变量。由于使用了synchronized关键字,可以保证在多线程环境下的线程安全性。但是,由于每次调用getInstance()方法都需要获取锁,这种实现方式在性能上并不高效。

问题2:如何实现双重检查锁定的单例?

为了提高懒汉式单例的性能,可以使用双重检查锁定(Double-Checked Locking)来实现。以下代码示例展示了一种双重检查锁定单例的实现方式:

public class DoubleCheckedSingleton {
    private static volatile DoubleCheckedSingleton instance;

    private DoubleCheckedSingleton() {
        // 私有构造方法,防止外部创建实例
    }

    public static DoubleCheckedSingleton getInstance() {
        if (instance == null) {
            synchronized (DoubleCheckedSingleton.class) {
                if (instance == null) {
                    instance = new DoubleCheckedSingleton();
                }
            }
        }
        return instance;
    }
}

在上述代码中,instance变量使用了volatile关键字修饰,确保了在多线程环境下的可见性。通过双重检查的方式,在第一次调用getInstance()方法时进行同步,避免了每次调用都需要获取锁的开销,提高了性能。

问题3:如何实现饿汉式单例?

饿汉式单例是指在类加载时即创建实例,以保证只有一个实例存在。以下代码示例展示了一种饿汉式单例的实现方式:

public class EagerSingleton {
    private static EagerSingleton instance = new EagerSingleton();

    private EagerSingleton() {
        // 私有构造方法,防止外部创建实例
    }

    public static EagerSingleton getInstance() {
        return instance;
    }
}

在上述代码中,instance变量在类加载时即被创建,并且通过getInstance()方法进行访问。由于在类加载过程中只会实例化一次,因此可以保证只有一个实例存在。

问题4:如何防止反射破坏单例模式?

通过反射可以访问和修改私有构造方法,从而破坏单例模式的实现。为了防止这种破坏,可以在构造方法中添加判断,当已有实例存在时抛出异常。以下代码示例展示了一种防止反射破坏单例的实现方式:

public class Singleton {
    private static Singleton instance;

    private Singleton() {
        if (instance != null) {
            throw new RuntimeException("Singleton instance already exists.");
        }
    }

    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

在上述代码中,当已有实例存在时,在构造方法中抛出运行时异常。这样,在尝试通过反射创建实例时,会