Java 7种单例模式的设计

本文介绍了Java中的7种单例模式,包括饿汉式、懒汉式、懒汉式+同步方法、Double-Check、Volatile+Double-Check、Holder方式和枚举方式。详细阐述了每种模式的特点,如饿汉式的即时初始化、懒汉式的延迟加载、枚举方式的线程安全等,并提及了可能出现的问题和解决方案。
摘要由CSDN通过智能技术生成

整理自汪文君老师著的《Java高并发编程详解》一书


Java 的 7种单例模式为:

  • 饿汉式
  • 懒汉式
  • 懒汉式 + 同步方法
  • Double-Check
  • Volatile + Double-Check
  • Holder方式
  • 枚举方式

代码与特点如下

1. 饿汉式
public final class Singleton1 {
    
    //实例变量
    private Object data = new Object();

    //在定义实例对象的时候直接初始化
    private static Singleton1 instance = new Singleton1();

    private Singleton1() { }

    public static Singleton1 getInstance(){
        return instance;
    }

}

特点:
该模式下instance对象在类加载过程中就被初始化了,data变量会一开始就占用推内存,如果该单例类被ClassLoader加载很长时间后才被使用,就意味着刚开始分配的堆内存有些浪费。
饿汉模式可以保证多线程下的唯一实例,但无法实现懒加载。

2. 懒汉式
public final class Singleton2 {

    private Object data = new Object();

    private static Singleton2 instance = null;

    private Singleton2() { }

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

特点:
实现了懒加载,但不能保证多线程环境下instance的唯一性;比如当两个线程同时执行到 instance == null 时,这时instance还为null,那么都会接着进行instance == new Singleton2(),会造成两次实例化。

3. 懒汉式 + 同步方法
public final class Singleton3 {

    private Object data = new Object();

    private static Singleton3 instance = null;

    private Singleton3() { }

    // 加入同步控制,保证同一时间只能有一个线程进入该方法
    public synchronized static Singleton3 getInstance() {
        if (instance == null) {
            instance = new Singleton3();
        }
        return instance;
    }
}

特点:
对饿汉模式的升级版,能百分百保证instance实例的唯一性,但是因为同一时间只能由一个线程获得该实例,性能比较低。

4. Double-Check
public final class Singleton4 {

    private Object data = new Object();
    private List<String> list;
    private Map<String,String> map; 
    private static Singleton4 instance = null;

    private Singleton4(){
        list = new ArrayList<>();
        map = new HashMap<>();
    }

    public static Singleton4 getInstance() {

        //当 instance 为 null 时,进入同步代码块。避免了每次调用 getInstance 方法时都必须同步,提高效率
        if(instance == null){
            //只能有一个线程能够获得Singleton.class关联的monitor
            synchronized(Singleton4.class){
                if(null == instance){
                    instance = new Singleton4();
                }
            }
        }
        return instance;
    }
}

特点:
既满足了懒加载,又保证了 instance 的唯一性;但是 在多线程情况下可能或引起 空指针异常,第一个线程在执行 instance = new Singleton4()语句时,instance、list、map的实例化顺序不是一定的,可能instance先被实例化,list 和 map还没有被实例化,但这时另一个线程判断到 instance 不为空,那么直接返回 instance 了,这时如果直接调用了 instance的 list 对象进行 add 操作,将会造成空指针异常。

5. Volatile + Double-Check
public final class Singleton5 {

    private Object data = new Object();
    private List<String> list;
    private Map<String, String> map;
    //加入 volatile 关键字保证类成员变量的实例话发生在instance之前
    private volatile static Singleton5 instance = null;

    private Singleton5(){
        list = new ArrayList<>();
        map = new HashMap<>();
    }

    public static Singleton5 getInstance() {

        // 当 instance 为 null 时,进入同步代码块。避免了每次调用 getInstance 方法时都必须同步,提高效率
        if (instance == null) {
            // 只能有一个线程能够获得Singleton.class关联的monitor
            synchronized (Singleton5.class) {
                if (null == instance) {
                    instance = new Singleton5();
                }
            }
        }
        return instance;
    }
}

特点:
加入了 volatile 关键字,防止了空指针异常;实现了懒加载、多线程下的示例唯一性以及获取实例的高效性

6. Holder方式
public final class Singleton6 {

    private Object data = new Object();

    static {
        System.out.println("这个类被实例化了");
    }

    private Singleton6() { }

    //在静态内部类中持有Singleton的实力,并且可被直接初始化
    private static class Holder{
        private static Singleton6 instance = new Singleton6();
    }

    // 调用 getInstance 方法,事实上是获得Holder的instance静态属性
    public static Singleton6 getInstance(){
        return Holder.instance;
    }
}

特点:
采用了内部类的方式,最好的单例设计方式之一,目前广为使用的设计之一

7. 枚举方式
public enum Singleton7 {

    INSTASNCE;
    
    private Object data = new Object();
    Singleton7(){ 
        System.out.println("INSTANCE will be initialized immediately");
    }

    public static void method(){
        //调用该方法则会主动使用Singleton,INSTANCE 将会被初始化
    }

    public static Singleton7 getInstance(){
        return INSTASNCE;
    }
}

特点
线程安全且只能被实例化一次,但是枚举类型不能够懒加载,比如如果调用其中的静态方法,则INSTANCE会立即得到示例话

另外一种 | 算是Holder和枚举的组合体
public final class Singleton8 {

    private Object data = new Object();

    private Singleton8() { }

    //使用枚举充当holder
    private enum EnumHolder{
        
        INSTANCE;
        private Singleton8 instance;
        EnumHolder(){
            this.instance = new Singleton8();
        }
        private Singleton8 getSingleton(){
            return instance;
        }
    }

    public static Singleton8 getInstance(){
        return EnumHolder.INSTANCE.getSingleton();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值