设计模式之单例模式面试总结

来源:互联网 发布:java商场系统 jeshop 编辑:程序博客网 时间:2024/06/06 04:59

单例模式
class SingleInstance {

private volatile static SingleInstance instance;

private SingleInstance() {}public static SingleInstance getInstance() {    if (instance == null) {                                          (i)        synchronized (SingleInstance.class) {            if (instance == null) {                instance = new SingleInstance();                     (j)            }        }    }    return instance;                                                 (k)}

}

1、不加任何同步锁的时候,当有两个线程同时执行到(j)处时,会创建两个instance实例对象。

2、双重检查也不是绝对安全的,因为JVM编译器可能对执行进行重排,new一个对象时不是原子操作。
一个对象的初始化正常顺序:
(1)memory=allocate();//分配对象的内存空间
(2)ctorinstance(memory)//初始化对象
(3)设置栈上的引用指向刚分配的内存地址。
但是重排后可能会出现:
(1)memory=allocate();//分配对象的内存空间
(3)设置栈上的引用指向刚分配的内存地址。
(2)ctorinstance(memory)//初始化对象。
  如果线程A执行到(i)处,线程B执行到(j)处,并且线程B执行了重排列后的指令(1)(3),这时A线程抢到CPU资源,判空时,发现instance不为空,就直接返回(K)处的instance对象,由于这个对象是未初始化过的对象,那么在用该对象调用实例方法时,就会出现程序异常。

3、双重检查加锁“的方式可以既实现线程安全(不保证绝对安全),又能够使性能不受到很大的影响。
  双重检测机制在获取对象实例的时候,先判空,如果对象实例为空时才同步,不为空时直接返 回对象,并不是像单层的那样每次获取都要同步,这样减少了每次进入都要同步的时间。

4、加了双重检测机制还可能不安全,那么可以在声明对象的前面加一个volatitle关键字
    这个关键字可以可以防止指令重排,也可以保证线程访问的变量值是主内存中的最新值。那么在双重检测的基础上,就能够保证线程的安全。

原创粉丝点击