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对序列化有保证。枚举实现单例的好处:有序列化和线程安全的保证,代码简单

  • 相关阅读:
    nginx能访问html静态文件但无法访问php文件
    LeetCode "498. Diagonal Traverse"
    LeetCode "Teemo Attacking"
    LeetCode "501. Find Mode in Binary Search Tree"
    LeetCode "483. Smallest Good Base" !!
    LeetCode "467. Unique Substrings in Wraparound String" !!
    LeetCode "437. Path Sum III"
    LeetCode "454. 4Sum II"
    LeetCode "445. Add Two Numbers II"
    LeetCode "486. Predict the Winner" !!
  • 原文地址:https://www.cnblogs.com/CodeGuy/p/3580486.html
Copyright © 2011-2022 走看看