• 7种单例模式


    一、什么是单例模式?
    单例模式,顾名思义就是 一个类只能有一个实例,并且在整个项目中都能访问到这个实例。

    二、Java中单例模式的7种写法及其分析
    写法一

     public class Singleton {
     
     private Singleton(){}
     
     private static Singleton instance = new Singleton();
     
     public static Singleton getInstance(){
     return instance;
     }
     }



    最简单的写法,缺点在于实例在类初始化的时候就创建了,如果在整个项目中都没有使用到该类,就会创建内存空间的浪费。

    写法二

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



    解决了写法一在类初始化的时候就创建实例的问题,然而只能在单线程中使用,在多线程中使用如果多个线程同时进入if语句中,就可能出现创建多个实例的问题。

    写法三

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



    解决了写法二可能出现的问题,可以在多线程中使用。缺点在于synchronized关键字会强制一次只能让一个线程进入方法中,其他线程不得不阻塞等待该线程退出方法。

    写法四

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



    解决了写法四出现的问题,缺点在于 JVM 在执行对引用赋值时并不是一个原子操作。具体是首先在堆中为 Singleton 分配内存空间,然后对 Singleton 执行初始化操作, 最后再将引用变量指向该实例所对应的内存地址以完成赋值。而 JVM 对这一步进行了优化,使得步骤二和步骤三可以不按顺序执行。所以就有可能出现一个线程在执行了步骤一之后执行了步骤三,然后另一个线程调用了该方法,此时 instance 引用变量不为空,然而 Singleton 实例还没有完成初始化,就会造成报错。

    写法五

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



    volatile关键字能够禁止指令重排,保证在写操作没有完成之前不能调用读操作。

    写法六

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



    这种写法的好处是充分利用了静态内部类的特点,它的初始化操作跟外部类是分开的。在没有调用 getInstance() 方法之前,静态内部类不会进行初始化,在第一次调用该方法后就生成了唯一一个实例。

    写法七

    public enum Singleton {
    
    INSTANCE;
    
    public void fun(){}
    
    }


    推荐写法,简单高效。充分利用枚举类的特性,只定义了一个实例,且枚举类是天然支持多线程的。

  • 相关阅读:
    【转】QT创建子对话框的方法
    IplImage转为Mat的方法
    浅谈Android选项卡(二)
    浅谈Android选项卡(一)
    Android来电、去电监听
    文件加密
    Java实现文件重命名
    使用单个httpclient实例请求数据。
    获取Android状态栏的高度
    [置顶] 微软翻译接口
  • 原文地址:https://www.cnblogs.com/braveLN/p/12072166.html
Copyright © 2020-2023  润新知