单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点到该实例。单例模式在很多场景下非常有用,特别是当某个类在整个应用程序中管理全局状态时,如配置管理器、连接池管理等。

请重点关注懒汉式和饿汉式

实现单例模式的关键点:

  1. 私有构造函数:防止外部直接使用new关键字创建类的实例。
  2. 私有静态实例:类的内部维护一个私有静态实例。
  3. 公共静态方法:提供一个公共的静态方法供外部访问,用于获取类的唯一实例。如果实例不存在,此方法将创建实例;如果已存在,直接返回该实例。

实现方式

1. 懒汉式(线程不安全)

懒汉式单例在首次使用时实例化自己,简单但线程不安全。

public class Singleton {
    private static Singleton instance;

    private Singleton() {}

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

2. 懒汉式(线程安全)

通过加锁synchronized保证线程安全,但每次访问都要加锁,影响性能。

public class Singleton {
    private static Singleton instance;

    private Singleton() {}

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

3. 饿汉式

饿汉式在类加载时就创建实例,保证线程安全,但可能造成资源浪费。

public class Singleton {
    private static final Singleton instance = new Singleton();

    private Singleton() {}

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

4. 双重校验锁(Double-Checked Locking)

双重校验锁既保证了懒加载,又保证了线程安全,且只在第一次创建实例时同步。

public class Singleton {
    private static volatile Singleton instance;

    private Singleton() {}

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

5. 静态内部类

使用静态内部类,利用JVM本身机制保证线程安全。这种方式既实现了懒加载,又保证了线程安全。

public class Singleton {
    private Singleton() {}

    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

6. 枚举实现

使用枚举方式,这是实现单例模式的最佳方法,不仅能避免多线程同步问题,还能防止反序列化重新创建新的对象。

public enum Singleton {
    INSTANCE;

    public void someMethod() {
        // 方法实现
    }
}

使用场景与优点

  • 资源共享:适用于访问共享资源的情况,如配置信息、硬件接口等。
  • 控制资源的使用:通过单例模式控制资源的创建,避免对资源的过度请求。
  • 全局访问点:提供了一个全局访问点,全局只有一个实例。

注意事项

虽然单例模式很有用,但也要注意其带来的问题,如隐藏了类之间的依赖关系,可能导致代码难以测试;在分布式系统中,需要额外的机制来确保全局唯一性等。