美文网首页
Java 单例模式及线程安全问题

Java 单例模式及线程安全问题

作者: 有梦想的狼 | 来源:发表于2020-08-26 10:03 被阅读0次

单例模式是指对一个对象进行一次实例化,然后全局都可以调用该实例化对象来完成项目的开发。

在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。这些应用都或多或少具有资源管理器的功能。每台计算机可以有若干个打印机,但只能有一个Printer Spooler,以避免两个打印作业同时输出到打印机中。每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被两个请求同时调用。总之,选择单例模式就是为了避免不一致状态,避免政出多头。

实现单例模式的方式

  1. 饿汉式
    饿汉式单例是指在方法调用前,实例就已经创建好了。下面是实现代码:

    //饿汉式
    public class SingletonE {
        //私有化构造方法,在外部不能实例化对象
        private SingletonE() {}
    
        /*
         * 实例化静态对象
         * 优点:不存在线程安全问题。
         * 缺点:系统加载时消耗额外资源,如果该实例没有使用的情况会造成资源浪费。
         */
        private static SingletonE instance = new SingletonE();
    
        //静态类方法
        public static SingletonE getInstance() {
            return instance;
        }
    }
    
  2. 懒汉式
    懒汉式单例是指在方法调用获取实例时才创建实例,因为相对饿汉式显得“不急迫”,所以被叫做“懒汉模式”。下面是实现代码:

    //懒汉式
    public class SingletonLan {
        //私有化构造方法,在外部不能实例化对象
        private SingletonLan() {}
    
        //申明静态对象
        private static SingletonLan instance;
    
        //静态类方法
        public static SingletonLan getInstance() {
            //以下代码不是原子性操作,会出现线程安全问题。
            if (instance == null) {
                instance = new SingletonLan();
            } 
            return instance;
        }
    }
    

    在以上代码中,在if语句里面,就可能跑有多个线程同步判断和同步new。会产生线程安全问题。

    解决方案:

    • 方案1:静态类方法加上线程锁(synchronized)
      这样就线程安全了,但是在多个线程访问环境下,同步方法会导致系统性能下降。
      不建议该方案
      //静态类方法
      public synchronized static SingletonLan getInstance() {
          if (instance == null) {
              instance = new SingletonLan();
        } 
        return instance;
      }
      
    • 方案2:双重检查锁定(Double-Check Locking)
      使用延时加载技术,避免类加载时任务过重和造成资源浪费,同时将synchronized关键字加在代码块中,减少线程同步锁定以提升系统性能。instance实例使用了volatile关键字修饰,主要是避免在多线程环境下由于编译器进行的重排序操作而导致的线程安全问题。JVM在创建一个对象时会进行以下步骤:
      1)分配对象内存空间;
      2)初始化对象;
      3)设置instance指向分配的内存地址;
      编译器为了优化性能,可能会将2、3操作调换顺序,假设A线程在执行new Singleton()方法时,由于2、3操作重排序,而初始化对象操作尚未完成时释放了锁。线程B获取锁之后会发现instance已经不为空,当线程B获取到instance对象后如果直接使用就会出错,原因就是对象没有进行初始化操作。而volatile关键字能避免重排序,因此能保证线程安全。总体上来说,双重检测由于加了锁,多线程并发下还是会有效率问题。下面是实现代码:
      //懒汉式--双重检查锁定
      public class SingletonLan {
          //私有化构造方法,在外部不能实例化对象
          private SingletonLan() {}
      
          /*
           * 申明静态对象
           * 加volatile关键字,是为了避免在多线程环境下由于编译器进行的重排序操作而导致的线程安全问题
           */
          private static volatile SingletonLan instance;
      
          //给外部提供一个访问该静态对象的静态方法
          public static SingletonLan getInstance() {
              //以下代码不是原子性操作,会出现线程安全问题。
              if (instance == null) {
                  synchronized (SingletonLan.class) {
                      if (instance == null) {
                          instance = new SingletonLan();
                      }
                  }
              } 
              return instance;
          }
      }
      
  3. 静态嵌套类单例

    //静态内部类单例(Static Inner Class)
    public class SingletonSIC {
        //私有化构造方法,在外部不能实例化对象
        private SingletonSIC() {}
    
        //静态类方法
        public static SingletonSIC getInstance() {
            return SingletonSICFactory.INSTANCE_SIC;
        }
    
        //申明一个静态内部类
        static class SingletonSICFactory{
            private static final SingletonSIC INSTANCE_SIC = new SingletonSIC();
        }
    }
    

    静态内部类单例模式是一种比较优秀的实现方式,也是《Effective Java》书中推荐的方式。一方面,使用延时加载,使用时才进行对象初始化,也不会造成造成资源浪费;另一方面,由于JVM在类的加载时已经做了同步处理,不会出现线程安全问题。

相关文章

  • 设计模式——单例模式的破坏

    概述: 之前学习了单例模式的几种实现,解决了多线程情况下,单例的线程安全问题,保证了单例的实现。但是单例模式在下面...

  • Singleton 单例模式

    饿汉式单例模式 饿汉式单例模式 通过静态代码块增加异常处理 懒汉式单例模式 存在线程安全问题 懒汉式单例模式 解决...

  • Java 单例模式及线程安全问题

    单例模式是指对一个对象进行一次实例化,然后全局都可以调用该实例化对象来完成项目的开发。 在计算机系统中,线程池、缓...

  • 单例记录

    如果单例中涉及到成员变量的修改和使用,则说明该类是有状态的,需要考虑线程安全问题。 java中的单例模式:饿汉,懒...

  • 单例模式之双重检查的演变

    前言 单例模式本身是很简单的,但是考虑到线程安全问题,简单的问题就变复杂了。这里讲解单例模式的双重检查。 单例模式...

  • Java多线程--并行模式与算法

    Java多线程--并行模式与算法 单例模式 虽然单例模式和并行没有直接关系,但是我们经常会在多线程中使用到单例。单...

  • 多线程Debug窥探单例模式

    1. 懒汉式单例模式 通过延迟初始化,降低单例创建期间的资源开销。 懒汉式单例实现,存在线程安全问题 线程任务 在...

  • 关于java静态内部类的思考

    前言 最近在看多线程,讲到单例模式安全问题的时候。提到了单例的第四种模式——InnerClass模式。里面提到这种...

  • 05.单例模式(创建型)

    创建型模式-单例模式 一、饿汉式单利模式 饿汉式不需要考虑线程安全问题。 饿汉式比较浪费资源 二、懒汉式单例模式 ...

  • Kotlin 的单例模式

    Kotlin 的单例模式 1. 在 Java 中的单例模式 懒汉式单例模式,并且是线程安全 2. 在 Kotlin...

网友评论

      本文标题:Java 单例模式及线程安全问题

      本文链接:https://www.haomeiwen.com/subject/vjczjktx.html