Dotcpp  >  编程教程  >  创建型模式(Creational Patterns)  >  单例模式

单例模式

点击打开在线编译器,边学边练

单例模式是一种创建型设计模式,它的目的是保证一个类只有一个实例,并提供一个全局的访问点来获取这个实例。

在软件开发中,有些类我们只需要一个实例就足够了,比如一个数据库连接池、线程池、日志系统或者系统配置信息。使用单例模式可以确保只有一个实例对象存在,这样可以节省内存资源和避免多个实例之间的冲突。

实现单例模式的关键

将类的构造函数设为私有,这样外部就无法直接创建对象。

提供一个静态方法来获取类的唯一实例,通常被称为getInstance()方法。在这个方法内部,我们可以控制对象的创建和返回。

下面是一个简单的Java示例,展示了如何实现单例模式:

public class Singleton {
    private static Singleton instance;
    private Singleton() {
        // 私有构造函数
    }
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

在这个例子中,Singleton类的构造函数被设为私有,防止外部通过 new 关键字直接创建对象。getInstance()方法检查实例是否已经存在,如果不存在,则创建一个新的实例并返回,如果存在,则直接返回现有实例。

需要注意的是,以上是一个简单的懒汉式单例模式的实现。在多线程环境下,为了确保线程安全,可以在getInstance()方法加锁或者使用双重检查锁定等机制。

当然,还有其他的单例模式实现方式,比如饿汉式单例、静态内部类单例等。每种实现方式都有其适用的场景和特点。

饿汉式单例(2种):

/**
 * 饿汉:在类刚一初始化的时候就立即把单例对象创建出来,下面两种都是饿汉模式的实现
 */
public class Singleton {
 
    private Singleton() {}
 
    private static Singleton instance = new Singleton();
    public static Singleton getInstance() {
        return instance;
    }
    private static Singleton instance1=null;
    static {
        instance1=new Singleton();
    }
    public Singleton getInstance1(){
        return instance1;
    }
 
}

懒汉式单例(4种):

/**
 * 懒汉:懒加载,就是在需要的时候才回去创建对象
 */
public class Singleton {
 
    private Singleton() {
    }
 
    /**
     * 1.单例模式【线程不安全,不推荐】
     * 因为没有加锁synchronized,严格意义上不算单例。
     * @return
     */
    private static Singleton instance1;
 
    public static Singleton getInstance() {
        if (instance1 == null) {//这里是不安全的,可能得到两个不同的实例
            instance1 = new Singleton();
        }
        return instance1;
    }
 
 
    /**
     * 2.线程安全但效率低【不推荐】
     * 99%的情况下不需要同步
     * @return
     */
    private static Singleton instance2;
 
    public static synchronized Singleton getInstance1() {
        if (instance2 == null) {
            instance2 = new Singleton();
        }
        return instance2;
    }
 
    /**
     * 3.单例模式,线程不安全【不推荐】
     * 虽然加了锁,但是等到第一个线程执行完instance2=new Singleton();跳出锁时
     * 令一个线程恰好刚判断完instance2为null,此时又会加载另一个实例
     */
    private static Singleton instance3;
 
    public static Singleton getInstance2() {
        if (instance3 == null) {
            synchronized (Singleton.class) {//不安全
                instance3 = new Singleton();
            }
        }
        return instance3;
    }
 
    /**
     * 4.双重校验锁:延迟加载+线程安全【推荐】
     */
    private static volatile Singleton instance4;
 
    public static Singleton getInstance4() {
        if (instance4 == null) {
            synchronized (Singleton.class) {
                if (instance4 == null) {
                    instance4 = new Singleton();
                }
            }
        }
        return instance4;
    }
}

静态内部单例:

/**
 * 静态内部类【推荐】
 * 这种方式跟饿汉式方式采用的机制类似,但又有不同。
 * 两者都是采用了类装载的机制来保证初始化实例时只有一个线程。
 * 不同的地方:
 * 在饿汉式方式是只要Singleton类被装载就会实例化,
 * 内部类是在需要实例化时,调用getInstance方法,才会装载SingletonHolder类
 * 优点:避免了线程不安全,延迟加载,效率高。
 */
public class Singleton {
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }
 
    private Singleton() {
    }
 
    public static final Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

枚举类单例:

/**
 * 枚举实现
 * 这种方式还没有被广泛采用,但是这种是实现单例的最佳方式。
 * 线程安全,自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化
 */
public enum Singleton {
    INSTANCE;
    public void whateverMethod(){
        System.out.println("单例模式实现的最佳方式");
    }
}

希望这个简单的介绍能够帮助你理解单例模式的基本概念和应用。


本文固定URL:https://www.dotcpp.com/course/1359

Dotcpp在线编译      (登录可减少运行等待时间)