设计模式-单例模式

        单例分为懒汉、饿汉模式。前者的实现比较多,但用于应用中不是必须使用的对象。后者实现简单。以下对比较成熟的实现方式做些介绍。

一、懒汉

1.双重校验锁

public class SingletonDoubleSyn {
    //防止JVM指令重排序,导致别的线程拿到instance!=null 但是又万未被初始化完成的对象
    private static volatile SingletonDoubleSyn instance;

    private SingletonDoubleSyn(){}

    public static SingletonDoubleSyn getInstance(){
        if (instance == null) {//1
            synchronized (SingletonDoubleSyn.class) {
                if(instance == null) {
                    instance = new SingletonDoubleSyn();//2
                }
            }
        }
        return instance;
    }
}

这里需要注意3点:

(1)、instance变量要加volatile关键字,为了防止JVM重排序。

  编译器会将这段代码 instance = new SingletonDoubleSyn();//2 编译成3句JVM指令:

        memory = allocate(); // 1   给instance对象分配内存

        init(memory);             // 2   初始化刚刚分配的内存

        instance = memory;  // 3    将分配的内存地址赋值到instance中

不过这2、3两条语句的执行顺序是不确定的,会在编译时指令重排序,如下所示:

        memory = allocate(); // 1   给instance对象分配内存

        instance = memory;  // 3    将分配的内存地址赋值到instance中

        init(memory);             // 2   初始化刚刚分配的内存

线程A执行到3的位置,此时恰好切换到线程B,B先判断instance == null,返回false,那此时B线程拿到的是为完成初始化的instance对象。

这一情况在变量前加上volatile可以避免。

(2)、因为绝大多数对instance的访问是读,因此只有在instance==null是才需要线程同步。

(3)、将构造方法私有化,保证单例。


2.静态内部类

public class SingletonByInnerClass {
    private SingletonByInnerClass(){}

    private static class SingletonHolder{
        //这里为什么要final修饰?
        private static final SingletonByInnerClass instance = new SingletonByInnerClass();
    }

    public static SingletonByInnerClass getInstance(){//1
        return SingletonHolder.instance;
    }
}

这里通过JVM的类加载机制(JVM对加载类时,做了同步机制),巧妙地避免了线程间的竞争。

声明一个变量不会触发JVM加载对应类,而当访问了类静态方法和静态变量时,会触发JVM加载类,类加载完成后会执行由编译器根据类中static变量,static方法,static块生成的init()方法,来初始化类。

不明白静态内部类中的变量为何要用final修饰?

JVM在对.class文件做了合法校验后,会在内存中(方法区)开辟一块区域,用以存放类变量,开辟完成后,会对新开辟的内存区域“清零”。如果一个变量被final修饰,该变量就在此时被赋值;如果没有final修饰,他会在对类的初始化中被赋值。无论哪种都能保证赋值,并不会被提前发布(不安全发布)。为什么要加final?


二、饿汉

public class SingletonHungry {
    private static SingletonHungry instance = new SingletonHungry();
    private SingletonHungry(){}

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值