单例模式

定义

单例模式确保某个类只有一个实例,并且自行实例化并向整个系统提供这个实例。java

特色

  • 单例类只能有一个实例
  • 单例类必须本身建立本身的惟一实例
  • 单例类必须给全部其余对象提供这一实例

单例模式的三种写法

饿汉式

public class Singleton{
       
       private static Singleton instance=new Singleton();
       //私有构造器,防止被屡次new建立
       private Singleton(){}
       
       public static Singleton getInstance(){
           return instance;
        }      
 
  }
  • 优势:这种写法比较简单,就是在类加载的时候就完成实例化。避免了线程同步问题。
  • 缺点:在类加载的时候就完成实例化,没有达到Lazy Loading的效果。若是从始至终都没使用过这个实例,则会形成内存的浪费。

静态内部类

public class Singleton{

    //私有构造器,防止被屡次new建立
    private Singleton(){}
    
    //把instance的实例放到静态类内部
    private static class SingletonInstance{
        private static final Singleton instance=new Singleton();
    }
    
    //调用getInstance方法时加载静态内部类
    public static Singleton getInstance(){
        return SingletonInstance.instance;
    }
)
  • 静态内部类方式在Singleton类被装载时并不会当即实例化,而是在须要实例化时,调用getInstance方法,才会装载SingletonInstance类。

双重检查(推荐)

public class Singleton{
    
    //volatile关键字确保多个线程正确地处理instance变量
    private volatile static Singleton instance;
    
    //私有构造器,防止被屡次new建立
    private Singleton(){}
    
    piblic static Singleton getInstance(){
        //第一次检查
        if(instance==null){
            synchronized(Singleton.class){
                //第二次检查
                if(instance==null){
                    instance=new Singleton();
                }
            }
        }
        return instance;
    }
}

为何instance须要用volatile修饰?
由于new Singleton()可能会发生重排序,具体能够分为三个步骤:
一、为对象分配内存
二、初始化对象
三、让instance指向内存地址
这种状况下可能会发生重排序,也就是变成1——>3——>2(单线程下并无改变结果,因此这是容许的,可是多线程下可能会返回未初始化的instance),所以须要volatile禁止重排序多线程

相关文章
相关标签/搜索