多线程下创建单例实例的方式

单例模式里有懒汉式和饿汉式,在多线程下需要用特殊的方式保证线程安全。
下面我用一种方式实现饿汉式单例,两种方式实现懒汉式单例

多线程下饿汉式单例:
//使用final修饰:防止子类覆盖父类中的方法,破坏单例

public final  class singleton implements Serializable {
    //构造方法私有化:防止其他类创建实例
    private singleton(){}
    //创建实例,将其设置为static和final
    private static final singleton INSTANCE=new singleton();
    //提供静态方法获取创建的实例
    public static singleton getInstance(){
        return INSTANCE;
    }
    //反序列化时,返回自己创建的实例而不是字节码生成的实例
    public Object readResolve(){
        return INSTANCE;
    }
}

多线程下懒汉式单例:DCL方式
public class singleton {
//私有化构造方法
private singleton(){}
//先定义实例化对象为null,并且用volatitle修饰
//加volatile的修饰的原因:因为同步代码块中的指令可能发生指令重排序,因为同步代码块内的构造方法和其赋值的指令,
//如果不加volatitle,这两个字节码指令可能会重排序,即先执行完赋值,再去调用构造方法
// 若此时有第二个线程来获取实例,则会产生错误(拿到的是没有调用构造前的值)
private static volatile singleton INSTANCE=null;
//创建实例的方法
public static singleton getInstance(){
if(INSTANCE!=null){
return INSTANCE;//第一个线程创建后实例后,其他线程就不用创建实例了
}
synchronized (singleton.class){
//在此处再次判断的原因是:假如有两个线程t1,t2,假设t1第一次执行,它先进行第一个判断,不成立,去获取锁,成功,进入同步
//代码块,去创建实例,还没有创建完成,这时t2线程执行到此,去获取锁,因为t1线程还持有锁,t2线程被阻塞住了,等t1线程
//创建实例完成,赋值完成,释放锁,退出同步代码块,t2线程获取到锁,进入同步代码块,此时如果不进行判断,t2线程也会去
//创建实例,这就不是单实例了
if(INSTANCE!=null){
return INSTANCE;
}
INSTANCE=new singleton();
return INSTANCE;
}

}

}

去掉注释:

public  class singleton  {
    private singleton(){}
    private static volatile singleton INSTANCE=null;
    public static singleton getInstance(){
        if(INSTANCE!=null){
            return INSTANCE;
        }
        synchronized (singleton.class){
            if(INSTANCE!=null){
                return INSTANCE;
            }
            INSTANCE=new singleton();
            return INSTANCE;
        }        
    }
}

多线程下懒汉式单例:使用静态内部类
public class singleton {

    //私有化构造方法
  private singleton(){}
  //定义静态内部类,创建实例
    private static class LazyHolder{
      static  final  singleton INSTANCE=new singleton();
  }
  //提供获取实例的方法
    public static singleton getInstance(){
      return LazyHolder.INSTANCE;
    }
}

//如何保证其单例的?
//因为静态内部类对外不可见,其加载方式也是懒汉式的,只有用到其实例时才创建
//比如,若是只使用singleton,而没有用getInstance(),不会触发静态内部类的加载,因而也不会去创建实例
//又由于类加载时创建的实例是JVM完成的,可以由JVM保证其线程安全性

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值