• 单例设计模式


    单例设计模式是最常用的设计模式之一,它提供了一种在多线程情况下保证实例唯一性的解决方案,单例模式虽然简单,但实现方式却有很多。
    采用单例模式,针对频繁使用的对象,可以省去new操作花费的时间,这对于哪些重量级对象而言,是可以省掉一笔非常可观的系统开销。
    对于new操作的次数减少,系统内存的使用频率也会降低,这将减轻GC压力,缩短GC停顿时间。
    因此,对于系统的关键组件和被频繁使用的对象,使用单例模式可以有效的改善系统的性能。

    1 饿汉式

    饿汉式指的是当类被加载的时候就实例化,并创建单例对象。如果类中的成员变量不多,且占用内存不大,这种方式也可以。如果类中的成员需要占用比较重的资源,就有点不妥。单例模式对象不能被继承,所以整个类用final修饰固化。

    package designpaten;
    public final class Singleton_Hungry {
          private static Singleton_Hungry instance  = new Singleton_Hungry();
         //构造函数私有化,不允许其他类直接通过new的方式创建新对象
          private Singleton_Hungry() {
        	  
          }
          public Singleton_Hungry getInstance() {
        	  return instance;
          }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2 懒汉式

    所谓的懒汉式指的就是只有在使用的时候才开始构造对象,这样可以避免在类加载的时候就提前创建。但这里要加锁,不然在多线程环境下可能会创建多个对象。

    package designpaten;
    public final class Singleton_Lazy {
          private static Singleton_Lazy instance  = null;
         //构造函数私有化,不允许其他类直接通过new的方式创建新对象
          private Singleton_Lazy() { 
          }
          public static synchronized Singleton_Lazy getInstance() {
        	  if(instance == null) {
        		  instance = new Singleton_Lazy();
        	  }
        	  return instance;
          }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    3 Double-check

    Dobule-check采用的也是一种同步机制,只不过是在首次初始化时加锁,之后就允许多个线程同时进行getInstance方法的调用来获得类的实例。

    package designpaten;
    public final class Singleton_DoubleCheck {
          private static Singleton_DoubleCheck instance  = null;
         //构造函数私有化,不允许其他类直接通过new的方式创建新对象
          private Singleton_DoubleCheck() { 
          }
          public static  Singleton_DoubleCheck getInstance() {
        	  if(instance == null) {
        		  synchronized(Singleton_DoubleCheck.class) {
        			  if(instance == null) {
                		  instance = new Singleton_DoubleCheck();
        			  }
        		  }
        	  }
        	  return instance;
          }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    4 Holder方法即内部类方式

    Holder方式完全是借助了类加载的特点。将instance成员放到了静态内部类Holder之中,因此单例类的初始化过程并不会创建单例实例。只有Holder被主动引用的时候才会创建单例实例。

    package designpaten;
    public final class Singleton_InnerClass {
          private static Singleton_InnerClass instance  = null;
         //构造函数私有化,不允许其他类直接通过new的方式创建新对象
          private Singleton_InnerClass() { 
          }
          private static class Holder{
        	  private static Singleton_InnerClass instance = new Singleton_InnerClass();
          }
          public static Singleton_InnerClass getInstance() {
        	  return Holder.instance;
          }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    5 枚举方式

    枚举类型不允许被继承,同样是线程安全的且只能被实例化一次,但是枚举类型不能够懒加载。也是高效JAVA编程作者推荐的方法。在这种实现方式中,既可以避免多线程同步问题;还可以防止通过反射和反序列化来重新创建新的对象。 因为Java虚拟机会保证枚举对象的唯一性,因此每一个枚举类型和定义的枚举变量在JVM中都是唯一的。

    package designpaten;
    //枚举类本身就是final的,不允许被继承
    public enum Singleton_Enum {
          INSTANCE;
          Singleton_Enum() {}
          public static Singleton_Enum getInstance() {
        	  return INSTANCE;
          }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    通过枚举定义单例,还有一种实现方式,就是将枚举类作为内部类来用。

    public class SingleDemo {
       private SingleDemo(){ 
       }
       public static enum Demo{
    	   INSTANCE;
    	   private  SingleDemo instance = null;
    	   private Demo() {
    		   instance= new SingleDemo();
    	   }
    	   public   SingleDemo create() {
    		   System.out.println("hello");
    		   return instance;
    	   }
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
  • 相关阅读:
    java基于微信小程序的游戏外包管理信息系统 uniapp 小程序
    校园日 | 看高校数据安全建设典型案例
    矩阵相关
    multisim仿真 数码管设计
    linux ls文件排序
    MySQL 慢查询经典案例分析
    该选择WPF 还是 Winform?
    软件需求说明书(GB856T-88)
    今日多写一行注释,明日维护少掉一根头发
    【C语言学习笔记---字符串函数】
  • 原文地址:https://blog.csdn.net/sunny_daily/article/details/128150959