单例模式

 Java Singleton模式主要作用是保证在Java应用程序中,一个类Class只有一个实例存在。 使用Singleton的好处还在于可以节省内存,因为它限制了实例的个数,有利于Java垃圾回收(garbage collection)

单例模式能够保证一个类仅有唯一的实例,并提供一个全局访问点。

什么情况下使用单例模式

单例模式也是一种比较常见的设计模式,它到底能带给我们什么好处呢?其实无非是三个方面的作用:

第一、控制资源的使用,通过线程同步来控制资源的并发访问;

第二、控制实例产生的数量,达到节约资源的目的。

第三、作为通信媒介使用,也就是数据共享,它可以在不建立直接关联的条件下,让多个不相关的两个线程或者进程之间实现通信。

比如,数据库连接池的设计一般采用单例模式,数据库连接是一种数据库资源。软件系统中使用数据库连接池,主要是节省打开或者关闭数据库连接所引起的效率损耗,这种效率上的损耗还是非常昂贵的。当然,使用数据库连接池还有很多其它的好处,可以屏蔽不同数据数据库之间的差异,实现系统对数据库的低度耦合,也可以被多个系统同时使用,具有高可复用性,还能方便对数据库连接的管理等等。数据库连接池属于重量级资源,一个应用中只需要保留一份即可,既节省了资源又方便管理。所以数据库连接池采用单例模式进行设计会是一个非常好的选择。

在我们日常使用的在Windows中也有不少单例模式设计的组件,象常用的文件管理器。由于Windows操作系统是一个典型的多进程多线程系统,那么在创建或者删除某个文件的时候,就不可避免地出现多个进程或线程同时操作一个文件的现象。采用单例模式设计的文件管理器就可以完美的解决这个问题,所有的文件操作都必须通过唯一的实例进行,这样就不会产生混乱的现象。

再比如,每台计算机可以有若干个打印机,如果每一个进程或者线程都独立地使用打印机资源的话,那么我们打印出来的结果就有可能既包含这个打印任务的一部分,又包含另外一个打印任务的一部分。所以,大多数的操作系统最终为打印任务设计了一个单例模式的假脱机服务Printer Spooler,所有的打印任务都需要通过假脱机服务进行。

实际上,配置信息类、管理类、控制类、门面类、代理类通常被设计为单例类。像Java的Struts、spring框架,.Net的Spring.NET框架,以及PHP的Zend框架都大量使用了单例模式。

单例模式主要有3个特点,:

1、单例类确保自己只有一个实例。

2、单例类必须自己创建自己的实例。

3、单例类必须为其他对象提供唯一的实例。

单例模式的实现方式:懒汉单例类和饿汉单例类


package cn_1;
/*
 *
 * 单例模式之饿汉式————(线程安全,效率高,但没有延时加载)
 * 用来确保只产生一个实例,并提供一个访问它的全局访问点.
 */
public class SingletonDemo1 {
 // 类初始化时,立即加载这个对象(没有延时加载的优势),线程是安全的
 private static SingletonDemo1 instance = new SingletonDemo1();
 public SingletonDemo1() {
 }
 // 方法没有同步,效率高
 public static SingletonDemo1 getInstance() {
  return instance;
 }
 
 // 测试
 public static void main(String[] args) {
  SingletonDemo1 s1=SingletonDemo1.getInstance();
  SingletonDemo1 s2=SingletonDemo1.getInstance();
  System.out.println(s1==s2);//由此说明它们是同一个对象
  
  //结果;true
 }
}


/*
 * 单例模式之懒汉式————(线程安全,效率低(因为每次都要调用 s2方法),延时加载)
 * (常用)
 */
public class SingletonDemo2 {
 private static SingletonDemo2 instance;
 public SingletonDemo2() {
 }
 //synchronized  保证同步,安全效率低
 public static synchronized SingletonDemo2 getInstance() {
  if (instance == null) {
   instance = new SingletonDemo2();
  }
  return instance;
 }
 // 测试
 public static void main(String[] args) {
  SingletonDemo2 s1 = SingletonDemo2.getInstance();
  SingletonDemo2 s2 = SingletonDemo2.getInstance();
  System.out.println(s1==s2);
 }
}

/*
 * 单例模式之双重检查锁实现
 * 注意:
 *     由于编译器优化原因和JVM底层内部模型原因
 *     偶尔会出问题,不建议使用。
 */
public class SingletonDemo3 {
 
  private static SingletonDemo3 instance = null;
 
  public static SingletonDemo3 getInstance() {
    if (instance == null) {
      SingletonDemo3 sc;
      synchronized (SingletonDemo3.class) {
        sc = instance;
        if (sc == null) {
          synchronized (SingletonDemo3.class) {
            if(sc == null) {
              sc = new SingletonDemo3();
            }
          }
          instance = sc;
        }
      }
    }
    return instance;
  }
 
  private SingletonDemo3() {
 
  }
   public static void main(String[] args) {
  SingletonDemo3 s1=SingletonDemo3.getInstance();
  SingletonDemo3 s2=SingletonDemo3.getInstance();
  System.out.println(s1==s2);

}

/*
* 单例模式之测试静态内部类实现
* 这种方式:线程安全,调用效率高,并且实现了延时加载!
*
*/
public class SingletonDemo4 {
private static class SingletonClassInstance {
 //final 可有可无
private static final SingletonDemo4 instance = new SingletonDemo4();
}
private SingletonDemo4(){
}
//方法没有同步,调用效率高!
public static SingletonDemo4  getInstance(){
return SingletonClassInstance.instance;
}
}

/*
* 单例模式之测试枚举式实现(没有延时加载)
*
*/
public enum SingletonDemo5 {
//这个枚举元素,本身就是单例对象!
INSTANCE;
//添加自己需要的操作!
public void singletonOperation(){
}

}
原文地址:https://www.cnblogs.com/rong123/p/10223975.html