Java中的单例模式详解(完整篇)

  

Java中的单例模式是一种常见的设计模式,它用于确保类只有一个实例,并提供全局的访问点。在某些场景下,单例模式可以提高系统的性能和效率。下面是单例模式详解的完整攻略:

什么是单例模式

单例模式(Singleton Pattern)是一种常见的创建型设计模式,它可以确保一个类只有一个实例,并提供全局的访问点。单例模式可以避免不必要的对象创建,提高系统的性能和效率。此外,在一个多线程的环境下,单例模式还可以避免竞态条件和锁竞争。

单例模式的实现

单例模式的实现一般有两种方法:饿汉式和懒汉式。

饿汉式

饿汉式是一种较为简单的单例模式实现方式,它的特点是类一旦加载就创建一个单例,保证在调用 getInstance 方法之前单例已经存在了。常见的实现方式如下:

public class Singleton {
    // 在类加载的时候就创建单例对象
    private static Singleton instance = new Singleton();
    // 私有构造函数,确保外部无法实例化该类
    private Singleton() {}
    // 获取单例的唯一访问点
    public static Singleton getInstance() {
        return instance;
    }
}

懒汉式

懒汉式是一种比较懒惰的单例模式实现方式,它的特点是单例的实例只会在第一次调用 getInstance 方法时被创建。常见的实现方式如下:

public class Singleton {
    // 声明单例,但暂时不创建单例对象
    private static Singleton instance = null;
    // 私有构造函数,确保外部无法实例化该类
    private Singleton() {}
    // 获取单例的唯一访问点
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

双重校验锁式

双重校验锁式是一种线程安全的懒汉式单例模式实现方式,它的特点是在需要时才会创建单例。通过双重校验锁,既避免了锁竞争,又避免了每次获取锁的开销。常见的实现方式如下:

public class Singleton {
    // 声明单例,但暂时不创建单例对象
    private static volatile Singleton instance = null;
    // 私有构造函数,确保外部无法实例化该类
    private Singleton() {}
    // 获取单例的唯一访问点
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized(Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

单例模式的使用

单例模式在实际开发中经常用于工具类、配置类、日志类等场景中。下面通过两个示例来说明单例模式的使用。

配置文件工具类

我们经常会用到配置文件来保存应用程序的配置信息。下面是一个配置文件工具类的示例,它可以读取和写入配置文件,并提供全局的访问点。

public class ConfigUtil {
    // 声明单例,但暂时不创建单例对象
    private static volatile ConfigUtil instance = null;
    // 保存配置信息的 Map
    private Map<String, String> configMap = new HashMap<>();
    // 私有构造函数,确保外部无法实例化该类
    private ConfigUtil() {
        // 初始化配置信息
        loadConfig();
    }
    // 加载配置信息
    private void loadConfig() {
        // 读取配置文件,将配置信息保存到 configMap 中
    }
    // 获取单例的唯一访问点
    public static ConfigUtil getInstance() {
        if (instance == null) {
            synchronized(ConfigUtil.class) {
                if (instance == null) {
                    instance = new ConfigUtil();
                }
            }
        }
        return instance;
    }
    // 获取配置信息
    public String getConfigValue(String key) {
        return configMap.get(key);
    }
    // 设置配置信息
    public void setConfigValue(String key, String value) {
        configMap.put(key, value);
    }
    // 保存配置信息到文件
    public void saveConfig() {
        // 将 configMap 中的配置信息写入配置文件
    }
}

日志记录器

日志记录器通常用于记录应用程序的运行日志。下面是一个简单的日志记录器的示例,它可以记录日志,并提供全局的访问点。

public class Logger {
    // 声明单例,但暂时不创建单例对象
    private static volatile Logger instance = null;
    // 日志文件的路径
    private String logFilePath = "";
    // 私有构造函数,确保外部无法实例化该类
    private Logger() {}
    // 获取单例的唯一访问点
    public static Logger getInstance() {
        if (instance == null) {
            synchronized(Logger.class) {
                if (instance == null) {
                    instance = new Logger();
                }
            }
        }
        return instance;
    }
    // 写入日志
    public void log(String message) {
        // 将日志写入日志文件
    }
    // 设置日志文件的路径
    public void setLogFilePath(String logFilePath) {
        this.logFilePath = logFilePath;
    }
}

单例模式的扩展

单例模式还可以通过一些扩展方式来增加功能或者优化性能,常见的扩展方式如下:

线程池化单例

线程池化单例是一种将多个单例对象缓存到线程池中,从而提高单例对象的重用率和系统的性能。

延迟加载单例

延迟加载单例是一种将单例对象的创建延迟到第一次使用时再进行,从而避免了不必要的对象创建。

总结

单例模式是一种常见的设计模式,它可以确保一个类只有一个实例,并提供全局的访问点,从而提高系统的性能和效率。单例模式的实现一般有饿汉式、懒汉式和双重校验锁式等方式。在实际开发中,单例模式经常用于工具类、配置类、日志类等场景中。单例模式还可以通过线程池化、延迟加载等方式进行扩展。

相关文章