单例模式

简介

  • 保证系统中只能存在某个类的一个实例。

要点

  1. 一个类只能有一个实例。
  • 需要定义一个该类的静态私有变量,使这个类的所有对象都共用这个实例。
  1. 实例必须由类自行创建。
  • 单例模式的类只能提供私有的构造函数。如此,才能保证外部无法实例化这个类的对象。
  1. 必须提供获取实例的方法。
  • 单例模式的类必须提供一个公共的静态函数用于创建或获取它本身的静态私有对象。

分类

饿汉式

  • 类一旦加载,就把实例初始化完成,不管需不需要用到这个实例。
public class Singleton{
    private static final Singleton instance = new Singleton();
    private Singleton(){}
    public Singleton getInstance(){
        return instance;
    }
}
  • 饿汉式天生就是线程安全的,可以直接用于多线程而不会出现问题。

懒汉式

  • 只有当第一次使用的时候,才会去初始化这个实例。

1.简单的实现

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

2.考虑多线程

  • 多线程同时访问Singleton类,访问getInstance方法时,可能会造成创建多个实例。可以给方法加一个锁。下面使用synchronized给getInstance方法加锁。
public class Singleton{
   private static Singleton instance = null;
   private Singleton(){}
   public synchronized Singleton getInstance(){
       if(instance == null){
           instance = new Singleton();
       }
       return instance;
   }
}

3.双重检查锁定

  • 每次调用getInstance方法的时候都要加锁,会影响性能。可以使用双重检查锁定,先判断instance是否为null,如果不为null,再加锁处理,这样不用每次都加锁。
public class Singleton{
   private static Singleton instance = null;
   private Singleton(){}
   public Singleton getInstance(){
       if(instance == null){
           synchronized(Singleton.class){
               if(instance == null){
                    instance = new Singleton();
               }
           }
       }
       return instance;
   }
}

4.防止指令重排序

  • 上面的双重检查锁定存在问题。instance() = new Singleton()这条语句在底层执行时有三个步骤,第1步是分配对象的内存空间,第2步是初始化对象,第3步是设置instance指向刚分配的内存地址。其中第2步和第3步可能发生重排序。如果线程A中发生了重排序,另一个并发执行的线程B有可能在进入getInstance()判断instance不为null。线程B接下来要访问instance所引用的对象,但此时这个对象可能还没有被A线程初始化!
  • 当声明instance的引用为volatile后,指令重排序在多线程环境中就会被禁止。
public class Singleton{
   private volatile static Singleton instance = null;
   private Singleton(){}
   public Singleton getInstance(){
       if(instance == null){
           synchronized(Singleton.class){
               if(instance == null){
                    instance = new Singleton();
               }
           }
       }
       return instance;
   }
}

5.基于类初始化实现懒汉式

  • JVM在类的初始化阶段,会执行类的初始化。在执行类的初始化期间,JVM会去获取一个锁。这个锁可以同步多个线程对同一个类的初始化。
public class Singleton{
    private static class InstanceHolder{
        public static Singleton instance = new Singleton();
    }
    private Singleton(){}
    public static Instance getInstance(){
        return InstanceHolder.instance;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值