java设计模式学习-单例模式

    java中单例模式定义:“一个类有且仅有一个实例,并且自行实例化向整个系统提供。”单例模式可以保证一个应用中有且只有一个实例,避免了资源的浪费和多个实例多次调用导致出错。

  单例模式有以下特点:
  1、单例类只能有一个实例。
  2、单例类必须自己创建自己的唯一实例。
  3、单例类必须给所有其他对象提供这一实例。

  所以相应的,我们用代码实现为:

  1.私有化该类的构造函数

  2.通过new在本类中创建一个本类对象

  3.提供一个共有的方法,给给类创建的对象返回

 

 1. 饿汉式写法

public class Singleton { //饿汉式
     int a=1;
     private Singleton(){};
     private static Singleton instance = new Singleton();
     public static Singleton getInstance(){
         return instance;
     }
调用方法:Singleton instance = Singleton.getInstance();

 

优点:饿汉式写法能保证线程安全,而且实现简单

缺点:在类加载的时候就完成了实例化,会造成内存浪费(可以忽略不计)

  2.懒汉式(线程不安全,不可用)

    public class Singleton {  
      
        private static Singleton instance=null;  
          
        private Singleton() {};  
          
        public static Singleton getInstance(){  
              
            if(instance==null){  
                instance=new Singleton();  
            }  
            return instance;  
        }  
    }  

因为只有在调用getInstance()这个方法的时候,才会去初始化这个单例,所以称为懒汉式

懒汉式存在线程安全问题,当2个或多个线程同时调用getInstance()方法时,有可能发生如下情况:当第一个线程在执行 if(instance==null)判断的时候,因为此时instance为空,他将会执行instance=new Singleton()来实例化对象,而第二个进程也同时进入了 if(instance==null)的判断,他可能会在第一个线程没有实例化之前进行判断,此时instance依旧为空,于是就实例化了2个Singleton对象,违背了单例模式。

于是,就有了懒汉式的双重校验锁

即加锁并且2次判断instance是否为空

 


public class Singleton {
private static volatile Singleton singleton = null;

private Singleton() {
}

public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
 

 

2次if(instance == null)校验,确保了线程安全,延迟加载,效率较高

volatile关键字禁止JVM对指令进行重排序,因为

singleton = new Singleton();是非原子性操作,原来的流程为先在栈中开辟空间存放singleton的引用,然后在堆中开辟空间存放实例化后的对象,栈中的引用指向堆中的new出来的地址
。JVM的优化会导致1、先在栈中开辟空间存放singleton的引用,2、然后堆中开辟空间后,3、引用指向堆中的空间,4、再进行实例化。此时在3之后,instance已经不为空,导致其他线程得到的可能是未实例化后的对象。

 

内部类

    public class Singleton{  
      
          
        private Singleton() {};  
          
        private static class SingletonHolder{  
            private static Singleton instance=new Singleton();  
        }   
          
        public static Singleton getInstance(){  
            return SingletonHolder.instance;  
        }  
    }  

和饿汉式类似,但又有不同。两者都是采用了类装载的机制来保证初始化实例时只有一个线程。不同

的地方在饿汉式方式是只要Singleton类被装载就会实例化,没有Lazy-Loading的作用,而静态内部类方式在Singleton类被装载时

并不会立即实例化,而是在需要实例化时,调用getInstance方法,才会装载SingletonHolder类,从而完成Singleton的实例化。

类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是

无法进入的。

优点:避免了线程不安全,延迟加载,效率高。

 

 

 
参考博客:

http://blog.csdn.net/dmk877/article/details/50311791



 

 


       

posted @ 2017-06-23 12:59  镜湖月色  阅读(173)  评论(0编辑  收藏  举报