创建型模式——单例模式

本文详细介绍了Java中实现单例模式的多种方法,包括懒汉式、饿汉式、静态内部类、双重检查锁定等,并对比了它们的线程安全性和效率。总结中指出,在没有特殊需求的情况下,推荐使用枚举或双重检查锁定的单例实现,以保证线程安全和延迟加载。
摘要由CSDN通过智能技术生成

一、介绍

单例模式是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

二、具体写法

1、懒汉式:线程不安全,没啥特殊嗜好就不要用
/**
 * 懒汉式:线程不安全,几乎不可使用
 *
 * @author zhangxs
 **/
public class FirstSingleton {
    private static FirstSingleton INSTANCE;

    private FirstSingleton() {
    }

    public static FirstSingleton getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new FirstSingleton();
        }
        return INSTANCE;
    }
}
2、懒汉式:线程不安全,不推荐使用
/**
 * 懒汉式:线程不安全,不推荐使用
 *
 * @author zhangxs
 **/
public class SecondSingleton {
    private static SecondSingleton INSTANCE;

    private SecondSingleton() {
    }

    public static SecondSingleton getInstance() {
        // 多线程同时进入,这里会导致多个实例的创建,后续改进为双重检查
        if (INSTANCE == null) {
            synchronized (SecondSingleton.class) {
                INSTANCE = new SecondSingleton();
            }
        }
        return INSTANCE;
    }
}
3、懒汉式:线程安全,效率较低,可用但不推荐
/**
 * 懒汉式:线程安全,效率较低,可用但不推荐,访问线程数量较多的情况下,不能及时得到响应
 *
 * @author zhangxs
 **/
public class ThirdSingleton {
    private static ThirdSingleton INSTANCE;

    private ThirdSingleton() {
    }

    public synchronized static ThirdSingleton getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new ThirdSingleton();
        }
        return INSTANCE;
    }
}
4、静态常量饿汉式:情况允许,可以使用
/**
 * 静态常量饿汉式:情况允许,可以使用
 *
 * @author zhangxs
 **/
public class FourthSingleton {
    private final static FourthSingleton INSTANCE = new FourthSingleton();

    private FourthSingleton() {
    }

    public static FourthSingleton getInstance() {
        return INSTANCE;
    }
}
5、静态代码块饿汉式:情况允许,可以使用
/**
 * 静态代码块饿汉式:情况允许,可以使用
 *
 * @author zhangxs
 **/
public class FifthSingleton {
    private final static FifthSingleton INSTANCE;

    static {
        INSTANCE = new FifthSingleton();
    }

    private FifthSingleton() {
    }

    public static FifthSingleton getInstance() {
        return INSTANCE;
    }
}
6、静态内部类方式:情况允许,可以使用
/**
 * 静态内部类方式:情况允许,可以使用
 *
 * @author zhangxs
 **/
public class SixthSingleton {
    private SixthSingleton() {
    }

    public static SixthSingleton getInstance(){
        return SingletonInstance.INSTANCE;
    }

    /**
     * 这个内部类和其内部的INSTANCE都是静态的,JVM类加载时可以保证唯一性
     * @author zhangxs
     * @date 2021-01-23 11:38
     */
    private static class SingletonInstance {
        private static final SixthSingleton INSTANCE = new SixthSingleton();
    }
}
7、双重线程安全检查,推荐使用,线程安全,延迟加载,效率较高
/**
 * 双重线程安全检查,推荐使用,线程安全,延迟加载,效率较高
 * 创建一个对象的三个步骤:
 *      1、分配内存空间给要创建的对象
 *      2、初始化对象时,调用构造器
 *      3、实例指向分配的内存地址
 * 之所以类中的静态成员变量加了volatile关键字,是为了防止重排序。由对象创建步骤我们可以看到,如果发生了重排序,实例指向分配的内存地址这个操作有可能前置到调用构造器之前,
 * 恰好CPU切换到其他线程执行,其他线程如果通过getInstance()中第一个if判断,直接拿到了前面的线程创建了但没有初始化的对象,会出现空指针的情况
 * @author zhangxs
 **/
public class SeventhSingleton {
    private volatile static SeventhSingleton INSTANCE;

    private SeventhSingleton() {
    }

    public static SeventhSingleton getInstance(){
        if(INSTANCE == null){
            synchronized (SeventhSingleton.class){
                if(INSTANCE == null){
                    INSTANCE = new SeventhSingleton();
                }
            }
        }
        return INSTANCE;
    }
}
8、枚举懒加载,推荐使用,最好的单例实现方式
/**
 * 枚举懒加载,推荐使用,最好的单例实现方式
 * 这种方式可以防止反射调用私有构造器来破坏单例,也可以避免反序列化破坏单例
 * @author zhangxs
 **/
public enum EighthSingleton {
    /** 对象实例 */
    INSTANCE;

    private String name;

    public void doSomething() {
        System.out.println(name + " is doing something now...");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

三、总结

没有更多特殊的要求,用枚举实现单例就完了,顶多双重线程安全检查的方式,其他的方式知道即可。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值