您的位置:

单例模式的实现方式

一、单例模式的概念

单例模式是一种创建型模式,它保证一个类只能被实例化一次,并提供了一个访问该实例的全局访问点。单例模式可以用来解决资源统一分配的问题,如线程池、全局缓存等。

单例模式的标准实现包含三个要素:1.私有的构造函数,2.静态变量实例,3.公共的访问方法。而实现单例模式的方式有很多,接下来我们将讨论这些实现方式。

二、单例模式的五种实现方式

下面是单例模式的五种实现方式:

饿汉式

public class Singleton {
    一个私有的、静态的、final类型的实例对象
    private static final Singleton INSTANCE = new Singleton();
    
    私有构造函数
    private Singleton() {}
    
    公开访问点
    public static Singleton getInstance() {
        return INSTANCE;
    }
}

饿汉式单例模式在类加载时已经创建了实例对象,因此不存在线程安全问题,但是如果实例对象很大,会导致启动时间变长。

懒汉式

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 {
    一个私有的、volatile类型的实例对象
    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 Singleton {
    私有构造函数
    private Singleton() {}
    
    私有静态内部类
    private static class SingletonHolder {
        一个私有的、静态的、final类型的实例对象
        private static final Singleton INSTANCE = new Singleton();
    }
    
    公开访问点
    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

静态内部类单例模式在外部类被加载的时候并不会被初始化,只有在调用公开访问点时才会初始化内部类,从而创建实例对象。这种方式既避免了饿汉式单例模式的启动时间长的问题,又避免了懒汉式单例模式的线程安全问题。

枚举

public enum Singleton {
    INSTANCE; 
    
    公开方法
    public void doSomething() {}
}

枚举单例模式是饿汉式单例模式的升级版,它天生就是线程安全的,并且可以防止反序列化创建新的实例对象。其优点在于简洁明了,不需要做额外的工作即可实现单例模式。

三、单例模式的几种实现方式

除了上述五种实现方式之外,还有一些单例模式的实现方式:

延迟初始化占位类

public class Singleton {
    私有变量
    private String data = "this is a lazy initialized singleton";
    
    私有构造函数
    private Singleton() {}
    
    私有静态内部类
    private static class Holder {
        私有静态变量
        private static final Singleton INSTANCE = new Singleton();
    }
    
    私有静态初始化方法
    private static final Singleton getInstance() {
        return Holder.INSTANCE;
    }
    
    公开访问点
    public String getData() {
        return data;
    }
}

延迟初始化占位模式是一种比较新颖的单例实现方式,它通过声明一个私有的静态内部类,该内部类包含单例的实例对象,并在第一次调用公开访问点时才初始化该实例对象,从而达到懒汉式单例模式的效果,并且不需要加锁保证线程安全。

ThreadLocal

public class Singleton {
    一个私有的ThreadLocal类型的实例对象
    private static ThreadLocal instance = new ThreadLocal
   () {{
        initialValue = new Singleton();
    }};
    
    私有构造函数
    private Singleton() {}
    
    公开访问点
    public static Singleton getInstance() {
        return instance.get();
    }
}

   
  

ThreadLocal单例模式是一种较为特殊的单例实现方式,它结合了懒汉式单例模式和多线程环境下线程安全的特性,并且在每个线程中都可以有自己独立的实例对象,从而达到可重入的效果。

四、单例模式的6种实现方式

除了上述介绍的五种实现方式之外,还有一种单例模式的实现方式,来看看它的实现:

注册式单例

public class Singleton {
    一个私有的静态Map类型的实例对象
    private static Map registry = new ConcurrentHashMap<>();
    
    静态代码块
    static {
        Singleton instance = new Singleton();
        registry.put(instance.getClass().getName(), instance);
    }
    
    protected Singleton() {}
    
    公共静态方法,返回指定名称的单例对象
    public static Singleton getInstance(String name) {
        if (name == null) {
            name = Singleton.class.getName();
        }
        if (registry.get(name) == null) {
            registry.put(name, new Singleton());
        }
        return registry.get(name);
    }
}

  

注册式单例模式将每个实例对象都注册到一个Map容器中,以便在需要时快速获取。该实现方式相对于其他实现方式来说比较复杂,而且需要考虑线程安全问题。

五、7种方式实现单例模式

虽然单例模式的标准实现方式只有三个要素,但是在实际使用的时候,我们还可以按照以下的七种方式来实现单例模式:

枚举

和上面的枚举单例模式一样,这里就不再重复介绍了。

饿汉式

和上面的饿汉式单例模式一样,这里就不再重复介绍了。

懒汉式

和上面的懒汉式单例模式一样,这里就不再重复介绍了。

双重检查

和上面的双重检查单例模式一样,这里就不再重复介绍了。

静态内部类

和上面的静态内部类单例模式一样,这里就不再重复介绍了。

延迟初始化占位类

和上面的延迟初始化占位类单例模式一样,这里就不再重复介绍了。

ThreadLocal

和上面的ThreadLocal单例模式一样,这里就不再重复介绍了。

六、实现单例模式的类具有

实现单例模式的类具有以下特点:

1.只能被实例化一次;

2.提供一个访问该实例的全局访问点;

3.在多线程环境下保证线程安全;

4.防止反序列化时创建新的实例对象。

七、单例模式的实现

以上方式都是通过私有的构造函数、静态变量以及公开访问点来实现单例模式的。

八、单例模式代码实现

下面是一个简单的单例模式实现的示例代码:

public class Singleton {
    一个私有的、静态的、final类型的实例对象
    private static final Singleton INSTANCE = new Singleton();
    
    私有构造函数
    private Singleton() {}
    
    公开访问点
    public static Singleton getInstance() {
        return INSTANCE;
    }
}

九、总结

单例模式是一种重要的设计模式,它可以帮助我们解决资源统一分配的问题,并且提升了程序的可维护性和可测试性。在实际开发中,我们可以选择适合自己的单例模式实现方式,并注意线程安全问题。