设计模式-单例模式

设计模式-单例模式

官方定义

所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例。并且该类只提供一个取得其对象实例的方法(静态方法)

举个最常见的例子,Spring中bean的默认都是单例模式,每个bean定义只生成一个对象实例,每次getBean请求获得的都是此实例

单例模式八种方式

那接下来我们来聊聊单例模式的八种实现方式,如下所示

  1. 饿汉式(静态常量)
  2. 饿汉式(静态代码块)
  3. 懒汉式(线程不安全)
  4. 懒汉式(线程安全,同步方法)
  5. 懒汉式(线程安全,同步代码块)
  6. 双重检查
  7. 静态内部类
  8. 枚举方式

饿汉式(静态常量)

//案例演示 - 饿汉式(静态常量)
class Singleton{
    //一、构造器私有化,防止外部用构造器初始化。。。
    private Singleton(){}
    //二、类的内部创建对象 final static
    private static final Singleton singleton = new Singleton();
    //三、对外提供公共的静态方法,返回该类的唯一对象
    public static Singleton getInstance(){
        return singleton;
    }
}

写法分析

优势:简单、避免多线程的同步问题

劣势:没有达到懒加载的效果

饿汉式(静态代码块)

class Singleton(){
    //构造器私有化
    private Singleton(){}
    //类的内部创建对象
    private static final Singleton singleton;
    
    static {
        singleton = new Singleton();
    }
    
    //对外提供公共的静态方法
     public static Singleton getInstance(){
        return singleton;
    }
}

写法分析

优势:简单,避免了多线程同步问题

劣势:没有实现懒加载效果

懒汉式(线程不安全)

class Singleton(){
    //构造器私有化
    private Singleton(){}
    //类的内部创建对象
    private static  Singleton singleton;
    //对外提供公共的静态方法
     public static Singleton getInstance(){
         if(singleton == null){
             singleton = new Singleton();
         }
        return singleton;
    }
}

写法分析

优势:起到了懒加载的效果,不会造成内存浪费

劣势:线程不安全,实际开发中不推荐这个方式

懒汉式(同步方法)

class Singleton(){
    //构造器私有化
    private Singleton(){}
    //类的内部创建对象
    private static  Singleton singleton;
    //对外提供公共的静态方法
     public static synchronized Singleton getInstance(){
         if(singleton == null){
             singleton = new Singleton();
         }
        return singleton;
    }
}

写法分析

解决了线程安全问题,但是效率太低

懒汉式(同步代码块)

class Singleton(){
    //构造器私有化
    private Singleton(){}
    //类的内部创建对象
    private static  Singleton singleton;
    //对外提供公共的静态方法
     public static  Singleton getInstance(){
         if(singleton == null){
             synchronized(Singleton.class){
             	singleton = new Singleton();
             }
         }
        return singleton;
    }
}

写法分析

不推荐,解决不了线程安全的问题

双重检查机制

class Singleton(){
    //构造器私有化
    private Singleton(){}
    //类的内部创建对象
    private static  Singleton singleton;
    //对外提供公共的静态方法
     public static  Singleton getInstance(){
         if(singleton == null){
             synchronized(Singleton.class){
                 if(singleton == null){
             			singleton = new Singleton();
                 }
             }
         }
        return singleton;
    }
}

写法分析

在实际开发中推荐使用这种方式

  1. 线程安全
  2. 懒加载
  3. 效率很高

可能出现的问题

我们认为的new Singleton()操作

  1. 分配内存地址M
  2. 在内存M上初始化Singleton对象
  3. 将M的地址值赋值给instance对象

JVM编译优化后(指令重排)可能的new Singleton()操作

  1. 分配内存地址M
  2. 将M的地址赋值给instance变量
  3. 在内存M上初始化Singleton对象

会出现空指针异常

解决方法

只需要关键字volatile 禁止指令重排

private static volatile  Singleton singleton;

扩展-Volatile

轻量级的同步机制(低配版)没有保证原子性

三大特性

  1. 保证可见性
    1. 其中一个线程修改了主内存共享变量的值,要写回主内存,并要及时通知其他线程可见
  2. 没有保证原子性
    1. (不能保证)不可以分割,完整,要么同时成功,要么同时失败
  3. 禁止指令重排
    1. 和底层内存屏障相关,避免多线程下出现指令乱序的情况

静态内部类方式

class Singleton{
    private Singleton(){}
    
    private static class SingLetonInstance{
        public static final Singleton INSTANG = new Singleton();
    }
    
    public static Singleton getInstance(){
        return SingletonInstance.INSTANG;
    }
}

写法分析

不会出现线程安全问题

JVM来帮我们保证线程的安全性‘

利用了静态内部类的特点,效率也很高,开发中推荐

枚举方式

enum Singleton{
		INSTANCE;
}

写法分析

不仅可以避免线程安全问题,推荐大家使用

posted @ 2021-02-24 22:32  吕敬瑛  阅读(119)  评论(0编辑  收藏  举报