剑指Offer——面二:实现Singleton模式

《剑指offer》笔记

设计一个类,我们只能生成该类的一个实例。

1、不好的解法:只适合单线程环境:将构造函数设为私有函数禁止他人创建实例

/**
* 单例模式,懒汉式,线程不安全
*/
    public static class Singleton2 {
        private static Singleton2 instance = null;

        private Singleton2() {

        }

        public static Singleton2 getInstance() {
            if (instance == null) {
                instance = new Singleton2();
            }

            return instance;
        }
    }

在单线程中工作正常,在多线程下(如果同时运行到判断instance是否为null语句时,若instance的确没有创建,那么两个线程会创建两个实例)
2、不好的解法:在多线程中能工作但效率不高

/**
* 单例模式,懒汉式,线程安全,多线程环境下效率不高
*/
public static class Singleton3 {
     private static Singleton3 instance = null;
     private Singleton3() {

     }

     public static synchronized Singleton3 getInstance() {
         if (instance == null) {
             instance = new Singleton3();
         }
         return instance;
     }
}

加同步锁是一个非常耗时的操作,在没有必要的情况下尽量避免。

3、可行的解法:加同步锁前后两次判断实例是否已存在
对解法二改进,在实例创建之前加锁,实例已经创建之后,不需要加锁

   /**
   * 静态内部类,使用双重校验锁,线程安全【推荐】
   */
   public static class Singleton7 {
       private volatile static Singleton7 instance = null;

       private Singleton7() {

       }

       public static Singleton7 getInstance() {
           if (instance == null) {
               synchronized (Singleton7.class) {
                   if (instance == null) {
                       instance = new Singleton7();
                   }
               }
           }

           return instance;
       }
   }

两次判断instance,避免违背单一性。提高了效率,但是实现复杂。

4、强推荐做法:利用静态构造函数

    /**
    * * 单例模式,饿汉式,线程安全
    */
    public static class Singleton {
        private final static Singleton INSTANCE = new Singleton();

        private Singleton() {

        }

        public static Singleton getInstance() {
                return INSTANCE;
        }
    }

在初始化静态变量INSTANCE时创建了一个实例,运行时能保证只调用一次静态构造函数,就可以保证只初始化一次instance.

5、强推方法:实现按需创建实例
解决方法4中创建实例过早的问题。

/**
* 单例模式,使用静态内部类,线程安全【推荐】
*/ 
public static class Singleton5 {
    private final static class SingletonHolder {
        private static final Singleton5 INSTANCE = new Singleton5();
    }

    private Singleton5() {

    }

    public static Singleton5 getInstance() {
       return SingletonHolder.INSTANCE;
    }
}

只有在运行到SingletonHolder.INSTANCE时得到Singleton5的实例,会自动调用SingletonHolder的静态构造函数创建实例INSTANCE。可以做到真正需要的时候创建实例,提高空间使用效率

猜你喜欢

转载自blog.csdn.net/u010843421/article/details/80881018