zoukankan      html  css  js  c++  java
  • JAVA中单例模式的几种实现方式

    1 线程不安全的实现方法

    首先介绍java中最基本的单例模式实现方式,我们可以在一些初级的java书中看到。这种实现方法不是线程安全的,所以在项目实践中如果涉及到线程安全就不会使用这种方式。但是如果不需要保证线程安全,则这种方式还是不错的,因为所需要的开销比较小。下面是具体的实现代码:

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

    我们说过这种实现方式不是thread-safe的,那么可以把上面的方法变成线程安全的吗?当然可以,在方法getInstance()上加上synchronized修饰符就可以实现方法的同步了。但是这样系统开销会很大。具体代码如下:

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

    每次有线程调用getInstance()方法,都需要同步判断。这显然不是最好的选择,下面将会陆续介绍几种thread-safe的方法。

    2 两种lazy loaded thread-safe的单例模式实现方式

    1) DCL (double checked locking 实现法)

        double checked locking ,顾名思义,就是双检查法,检查实例INSTANCE是否为null或者已经实例化了。下面是具体的实现代码:

     1 public class DoubleCheckedLockingSingleton{
     2      private volatile DoubleCheckedLockingSingleton INSTANCE;
     3  
     4      private DoubleCheckedLockingSingleton(){}
     5  
     6      public DoubleCheckedLockingSingleton getInstance(){
     7          if(INSTANCE == null){
     8             synchronized(DoubleCheckedLockingSingleton.class){
     9                 //double checking Singleton instance
    10                 if(INSTANCE == null){
    11                     INSTANCE = new DoubleCheckedLockingSingleton();
    12                 }
    13             }
    14          }
    15          return INSTANCE;
    16      }
    17 }

    这种方法也很好理解,我们可以看到有两次对instance是否为null的判断:如果第一次判断不为空,则直接返回实例就可以了;如果instance为空,则进入同步代码块再进行null值判断,再选择是否实例化。第一个null判断可以减少系统的开销。在实际项目中做过多线程开发的都应该知道DCL。

    2) lazy initialization holder class 模式实现法

    下面是这种方法的实现代码:

    public class Singleton {
        /**
         * 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例
         * 没有绑定关系,而且只有被调用到才会装载,从而实现了延迟加载
         */
        private static class SingletonHolder{
            /**
             * 静态初始化器,由JVM来保证线程安全
             */
            private static Singleton instance = new Singleton();
        }
        /**
         * 私有化构造方法
         */
        private Singleton(){
        }
        public static  Singleton getInstance(){
            return SingletonHolder.instance;
        }
    }

    当getInstance方法第一次被调用的时候,它第一次读取SingletonHolder.instance,导致SingletonHolder类得到初始化;而这个类在装载并被初始化的时候,会初始化它的静态域,从而创建Singleton的实例,由于是静态的域,因此只会被虚拟机在装载类的时候初始化一次,并由虚拟机来保证它的线程安全性。这个模式的优势在于,getInstance方法并没有被同步,并且只是执行一个域的访问,因此延迟初始化并没有增加任何访问成本。

    关于延迟初始化(lazy loaded

    “除非绝对必要,否则就不要延迟初始化”。延迟初始化是一把双刃剑,它降低了初始化类或者创建实例的开销,却增加了访问被延迟初始化的域的开销,考虑到延迟初始化的域最终需要初始化的开销以及域的访问开销,延迟初始化实际上降低了性能。

    3 静态工厂实现法

      因为单例是静态的final变量,当类第一次加载到内存中的时候就初始化了,其thread-safe性由JVM来负责保证。值得注意的是这个实现方式不是lazy-loadedd的。   具体实现代码如下:

     1 public class Singleton{
     2     //initailzed during class loading
     3     private static final Singleton INSTANCE = new Singleton();
     4  
     5     private Singleton(){}
     6  
     7     public static Singleton getSingleton(){
     8         return INSTANCE;
     9     }
    10 }

    枚举实现单例(Enum Singleton)

      枚举单例(Enum Singleton)是实现单例模式的一种新方式,枚举这个特性是在Java5才出现的,在《Effective Java》一书中有介绍这个特性。下面是这种方法的具体实现代码:

    public enum Singleton {  
        INSTANCE("hello") {  
            public void someMethod() {  
                // . . .  
            }  
        };  
        private String name;
        private void PrintName(){System.out.println(name);}
        protected abstract void someMethod();  
    } 

    你可以通过Singleton.INSTANCE来访问该单示例变量。默认枚举实例的创建是线程安全的,但是在枚举中的其他任何方法由程序员自己负责。如果你正在使用实例方法,那么你需要确保线程安全(如果它影响到其他对象的状态的话)。传统单例存在的另外一个问题是一旦你实现了序列化接口,那么它们不再保持单例了,但是枚举单例,JVM对序列化有保证。枚举实现单例的好处:有序列化和线程安全的保证,代码简单

  • 相关阅读:
    Python 用 matplotlib 中的 plot 画图
    python--serial串口通信
    verilog,vhdl,bdf文件一起综合
    项目小笔记2--qt designer 修改字体,部件拖入layout,引用time模块延时,正则表达式判断输入,进制转换,部件固定大小,graphics view显示图片,消息提示框使用
    虚拟环境下通过pyinstaller 打包
    FPGA--IIC通信
    FPGA--SPI通信
    verilog 语法
    【C_Language】---队列和栈的C程序实现
    【C_Language】---C文件学习
  • 原文地址:https://www.cnblogs.com/CodeGuy/p/3580486.html
Copyright © 2011-2022 走看看