• 亮点面试题&&实现Singleton(辛格尔顿)模式-JAVA版本


    称号:设计一个类。我们只能产生这个类的一个实例。(来自《剑指Offer》)
    解析:仅仅能生产一个实例的类是实现Singleton(单例)模式的类型。因为设计模式在面向对象程序设计中起着举足轻重的作业,在面试过程中非常多公司都喜欢问一些与设计模式相关的问题。

    在经常使用的模式中,Singleton是唯一一个可以用短短几十行代码完整实现的模式。

    因此,写一个Singleton的类型是一个非经常见的面试题。


    下面我们给出几种解法。供大家參考。


    *不好的解法一:仅仅适用于单线程环境。


    因为要求仅仅能产生一个实例。因此我们必须把构造函数设为私有函数以禁止他人创建实例。我们能够定义一个静态的实例,在须要的时候创建该实例。基于这个思路的实现:
    public class Singleton1{
    private Singleton1(){
    }
    private final static Singleton1 instance = null;
    public static Singleton1 getInstance(){
    if(instance == null)
    instance = new Singleton1();
    return instance;
    }
    }
    上述代码在Singleton1的静态属性Instance中,仅仅有在instance为null的时候才创建一个实例以避免反复创建。同一时候。我们把构造函数定义为私有函数,这样就能确保仅仅创建一个实例。




    *不好的解法二:尽管在多线程环境中能工作但效率不高
    解法一中的代码在单线程的时候工作正常。但在多线程的情况下就有问题了。设想假设两个线程同一时候执行到推断instance是否为null的if语句。而且instance的确没有创建时,那么两个线程都会创建一个实例,此时类型Singleton1就不再满足单例模式的要求了。

    为了保证在多线程环境下我们还是仅仅能得到类型的一个实例,须要加上一个同步锁。把Singleton1稍做改动得到了例如以下代码:
    public class Singleton2 {
       private static Singleton2 instance = null;
       private Singleton2() { }


       public static synchronized Singleton2 getInstance() {
          if(instance == null) {
             instance = new Singleton2();
          }
          return instance;
       }
    }
    我们还是如果有两个线程同一时候想创建一个实例。因为在一个时刻仅仅有一个线程能得到同步锁。当第一个线程加上锁时,第二个线程仅仅能等待。当第一个线程发现实例还没有创建时,它创建出一个实例。接着第一个线程释放同步锁,此时第二个线程能够加上同步锁,并执行接下来的代码。这个时候因为实例已经被第一个线程创建出来了,第二个线程就不会反复创建实例了,这样就保证了我们在多线程环境中也仅仅能得到一个实例。
    可是类型Singleton2还不是非常完美。我们每次通过属性Instance得到Singleton2的实例,都会试图加上一个同步锁,而加锁是一个非常耗时的操作。在没有必要的时候我们应该尽量避免。
    **可行的解法一:加同步锁前后两次推断实例是否已存在
    我们仅仅是在实例还没有创建之前须要加锁操作,以保证仅仅有一个线程创建实例。而当实例已经创建之后,我们已经不须要再加锁操作了。所以我们改进例如以下:
    public class Singleton3 {
       private static Singleton3 instance = null;
       private Singleton3() { }
       public static Singleton3 getInstance() {
          if(instance == null) {
             synchronzied(Singleton3.class) {
                Singleton3 temp = instance;
                if(temp == null) {
                   temp = new Singleton3();
                   instance = temp
                }
             }
          }
          return instance;
       }
    }
    因为指令重排序问题,所以不能够直接写成以下这样:
    public class Singleton3 {
       private static Singleton3 instance = null;
       private Singleton3() { }
       public static Singleton3 getInstance() {
          if(instance == null) {
             synchronzied(Singleton3.class) {
                if(instance == null) {
                   instance = new Singleton3();
                }
             }
          }
          return instance;
       }
    }
    可是假设instance实例变量用volatile修饰就能够了,volatile修饰的话就能够确保instance = new Singleton();相应的指令不会重排序,例如以下的单例代码也是线程安全的:
    public class Singleton3 {
       private static volatile Singleton3 instance = null;
       private Singleton3() { }
       public static Singleton3 getInstance() {
          if(instance == null) {
             synchronzied(Singleton3.class) {
                if(instance == null) {
                   instance = new Singleton3();
                }
             }
          }
          return instance;
       }
    }
    Singleton3用加锁机制来确保在多线程环境下仅仅创建一个实例,而且用俩个if推断来提高效率。

    这种代码实现起来比較复杂,easy出错,我们还有更优秀的解法。


    **强烈推荐的解法二:借助内部类
    这样的方法属于懒汉式单例,由于Java机制规定,内部类SingletonHolder仅仅有在getInstance()方法第一次调用的时候才会被载入(实现了lazy)。并且其载入过程是线性安全的。内部类载入的时候实例化一次instance。
    public class Singleton {


       private Singleton() { }  
        private static class SingletonHolder {
          private final static Singleton INSTANCE = new Singleton();
       } 
        public static Singleton getInstance() {
          return SingletonHolder.INSTANCE;
       }
    }
     


     

    版权声明:本文博客原创文章,博客,未经同意,不得转载。

  • 相关阅读:
    JAVA-初步认识-第三章-语句-switch
    JAVA-初步认识-第三章-if语句练习-星期和季节
    第三章-数据类型(3.3)
    JAVA-初步认识-第三章-局部代码块
    JAVA-初步认识-第三章-语句-if格式3
    JAVA-初步认识-第三章-语句-if格式1的演示
    JAVA-初步认识-第三章-语句-if格式2
    微信小程序图片使用示例
    推荐一款稳定快速免费的前端开源项目 CDN 加速服务
    基于mpvue的小程序项目搭建的步骤
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/4653873.html
Copyright © 2020-2023  润新知