1、定义:单例模式(Singleton),保证一个类仅有一个实例,并提供一个访问它的全局访问点。

2、什么时候用呢?

  • 资源共享的情况下
    应用程序日志应用,一般都用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。
    Web应用的配置对象的读取,一般也应用单例模式,这个是由于配置文件是共享的资源。
  • 控制资源的情况下
    数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。数据库软件系统中使用数据库连接池,主要是节省打开或者关闭数据库连接所引起的效率损耗,这种效率上的损耗还是非常昂贵的,用单例模式来维护,就可以大大降低这种损耗。
    多线程的线程池的设计一般也是采用单例模式,这是由于线程池要方便对池中的线程进行控制。
 
3、好处
  • 保证唯一实例
  • 可以严格地控制客户怎么访问它。对唯一实例的受控访问

4、实现思路

  • 让类自己保存它唯一的实例
  • 构造方法私有化
  • 提供一个访问该唯一实例的方法

5、编程实现

  有很多种编程实现方式,这里介绍两种经典的:懒汉式、饿汉式

  1)懒汉式,顾名思义,不着急实例化自己,等第一次用到的时候再实例化

    a.最基本的情况

public class Singleton {
       private static Singleton single=null;//内部保存自己的实例
       private Singleton(){} //构造方法私有化,保证只有自己能实例化自己
       // 静态工厂方法
       public static Singleton getInstance(){ //提供一个访问自身实例的方法
              if (single==null) {
                     single=new Singleton();     //若这个实例不存在,则创建它
              }
              return single;
       }
}

  评价:在多线程的情况下,这是不安全的,考虑多线程的安全问题,有以下三种改进方式

 

    b. 在getInstance的方法上加同步

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

  评价:就多了一个同步的“synchronized”关键字,同步方法,别的调用不会进入到该方法,如此保证唯一性

  不足:同步是针对方法的,以后每次调用该方法时(即使已经创建了实例),也会进行同步,造成不必要的同步开销。【不推荐】

 

    c. 双重检查锁定

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

  评价:先判断实例是否存在,不存在的情况下,使用同步锁,再检查实例是否存在,不存在则创建。

  改进之处:只有在实例不存在的情况下,才同步,减少了不必要的同步开销

 

    d. 静态内部类【推荐】

public class Singleton {
       private Singleton(){}
       private static class LazyHolder{
              private static final Singleton INSTANCE=new Singleton();
       }
       public static final  Singleton getInstance(){   
              return LazyHolder.INSTANCE;
       }
}

  评价:在静态内部类中实例化,利用了类加载机制,不存在多线程并发的问题。不一样在于,在内部类里面去创建对象实例,只要应用中不使用内部类,JVM就不会去加载这个单例类,也就不会创建单例对象,从而实现懒汉式的延迟加载。

  唯一性的原理是什么????

 

  2)饿汉式,听这名字就很饥渴,被加载的时候就迫不及待把自己实例化了

public class Singleton {
	private Singleton(){}
	private static final Singleton SINGLETON=new Singleton(); //直接实例化自己
	public static  Singleton getInstance(){	
		return SINGLETON;
	}
}

在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以天生是线程安全的。