zoukankan      html  css  js  c++  java
  • 设计模式(二)--单例模式

      单例模式是最常见的设计模式,也是项目中或者框架中应用比较广泛的设计模式,今天一起复习的一下单例模式的几种写法。
     
    单例模式优点:
      1.保证只有一个实例,所以可以节省内存和计算。
      2.有些场景下,可以保证结果正确。
      3.方便管理。
     
    使用场景:
      1.无状态的工具类,例如日期工具类,字符串工具类等。
      2.全局信息类。
     
    恶汉模式一:不推荐
    public class Singleton {
    
        private final static Singleton instance = new Singleton();
    
        private Singleton(){
    
        }
    
        public static Singleton getInstance() {
            return instance;
        }
    }

       将实例设置为static,保证只被加载一次,构造器私有化,时间上首先将实例加载,所以是恶汉模式。

    恶汉模式二:不推荐

    public class Singleton {
    
        private static final Singleton instance;
    
        static {
            instance = new Singleton();
        }
    
        private Singleton(){
    
        }
    
        public Singleton getInstance() {
            return instance;
        }
    }
      实现和第一种方式几乎完全一样,特点也是一样。
    懒汉模式一:不安全
    public class Singleton {
    
        private static Singleton instance;
    
        private Singleton(){
    
        }
    
        public static Singleton getInstance() {
            if (instance == null) {
                instance = new Singleton();
            }
            return instance;
        }
    }

       懒汉模式用时间换内存空间,直到使用的时候才会加载,但是他是线程不安全的,if(instance == null)的判断在多线程场景下同时进入,然后会创建多个实例,那样就不是单例了,所以,需要保证同步,也就是下一种方式。

    懒汉模式二:不推荐
    public class Singleton {
    
        private static Singleton instance;
    
        private Singleton(){
    
        }
    
        public static synchronized Singleton getInstance() {
            if (instance == null) {
                instance = new Singleton();
            }
            return instance;
        }
    }

       通过synchronized关键字修饰static方法,现在可以保证原子性,同一时间,只有一个线程进入方法,是线程安全的。但是带来的效率问题,只有一个线程进入方法,其他线程都是Blocked状态,所以不推荐使用,有点太粗暴了。

    懒汉模式三:不安全

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

       这样的写法应该一下就发现问题了,虽然用同步块保证同一时间创建实例的时候只有一个线程,但是已经进入了判断,还是会创建多个线程。

    双重检查:推荐

    public class Singleton {
    
        //需要volatile修饰,以此保证可见性和有序性
        private static volatile Singleton instance;
    
        private Singleton(){
    
        }
    
        public static Singleton getInstance() {
            if (instance == null) {
                synchronized (Singleton.class) {
                    if (instance == null) {
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }
    }

      上一种方法说了会创建多个实例,所以在同步块内部加了非空判断,也就是双重检查,保证只有一个实例。如果只是这样,还忽略一个问题,就是instance = new Singleton();不是一个原子性操作,实际上有三个步骤:

      1.给对象分配内存

      2.调用构造函数初始化成员变量

      3.将对象赋值给instance

      这时候可能发生CPU乱序执行,可能是1-3-2的步骤,只要执行第三部,instance就不是null了,然后其他线程直接返回instance,但此时没有进行初始化,变量都未被赋值的,很有可能出现问题,所以需要用volatile修饰。

    优点:

      1.线程安全

      2.延迟加载

      3.效率较高

    静态内部类:推荐
    public class Singleton {
    
        private Singleton(){
    
        }
    
        private static class Inner{
            private final static Singleton instance = new Singleton();
        }
    
        public static Singleton getInstance() {
            return Inner.instance;
        }
    }

       这种也是懒汉模式,只有需要的时候,才会进行初始化,而且静态内部类保证线程安全。

    枚举实现:最优

    public enum  Singleton {
    
        INSTANCE;
    }

      枚举实现方式,超级简单,调用只需要Singleton.INSTANCE就是实例了,进而进行其他操作处理。Joshua Bloch在《Effective Java》说过:枚举就是实现单例的最佳方式。枚举实例上是final class,继承枚举父类,其方法都是static方法。

    优点:
      1.实现简单优雅。
      2.线程安全。
      3.可以避免被反射和反序列化破坏,这是其它方式所没有的。

  • 相关阅读:
    2014 中华架构师大会 回想
    mybatis重拾---部署官方demo
    D 语言学习感受
    D语言学习
    D语言简介
    C++输入cin详解
    C++源文件的后缀名问题
    C 函数指针详解
    Linux下的五个查找命令:grep、find、locate、whereis、which
    Qt---QFtp上传、下载二进制文件
  • 原文地址:https://www.cnblogs.com/huigelaile/p/12026814.html
Copyright © 2011-2022 走看看