问答法学习单例模式

最近一直在刷数据结构(leetcode),嘿嘿,看看之前写的专栏一直没有动手,哎,不是我不想写,是因为积累确实没到

如同军人没经历过几场百团大战,你能让他去带军大战么,这不是纸上谈兵么

好了回归正题:

单例其实很简单,但其实里面还是有很多知识点可以学习,

  • 比如static修饰的东西(方法或者变量),在程序中是什么时候加载的?
  • 多线程中的volatile,synchronized?
  • 内部类在java中的加载机制?

这三个问题搞定基本常用的单例就说完了

准备好就打开sublime开撸吧,别跟我说你是用ide准备写代码,ide中写的代码永远不是你的水平,面试的时候,你还是得手写呢

我是已经手写一遍了,嗯,写的还不错就是有几个单词忘记了(>﹏<。)

1.饿汉模式

其实这种模式对于我们开发者来说才是真正的懒汉模式,直接用一个static修饰变量,一个方法返回就行了

/**
 * 饿汉模式
 */
public class Singleton{

    private static Singleton sl=new Singleton();

    public static Singleton getInstance(){
        return sl;
    }
    public void sayhello(){
        System.out.println("say hello");
    }
}

我们来说第一个问题

比如static修饰的东西(方法或者变量),在程序中是什么时候加载的?

static修饰的东西,在程序一开始加载中,内存单独开启了一块区域给静态变量区域,他们是最先被加载的,而对象的引用都会指向同一个内存区域

总结:

优点:写起来简单,容易实现,多线程安全
缺点:没有考虑使用的时候才进行加载

2.懒汉模式

懒汉模式呢,就比较多版本,当然我也是一步一步写的

第一个版本,解决用时加载问题,当然是没有考虑到多线程使用

/**
 * 懒汉式单例
 */
public class Singleton {

    private static Singleton sl=null;

    public static Singleton getInstance(){
        if(null==sl){
            sl=new Singleton();
        }
        return sl;
    }
}

第二个版本呢,纠结了多线程的问题了,这里就用到了synchronized关键字了

/**
 * 线程安全的耗时做法
 */
public class Singleton{

    private static Singleton sl=null;

    public static synchronized  Singleton getInstance(){
    if(null==sl){
        sl=new Singleton();
    }
        return sl;
    }
}

第三个版本呢,直接用synchronized同步整个方法很耗时呢,毕竟有可能他不为空呢,你也去同步是不是就多此一举呢

public class Singleton {

    private static volatile Singleton sl = null;

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

细心的朋友,应该会想,是不是缺了点什么,因为单例大家都知道用,也会写

你们再看看,是不是多了一个volatile关键字

这里引出了二个问题

多线程中的volatile,synchronized使用

在单例中呢,synchronized使用了同步代码块,但是呢,如果不加volatile,就会出错为什么呢?

关键在于sl = new Singleton(); 在内存中是这样的

inst = allocat(); // 分配内存  
sSingleton = inst;      // 赋值
constructor(inst); // 真正执行构造函数

为什么会这样呢,因为jvm优化,指令重排序,赋值在前面,真正去执行构造函数可能在后面,而volatile就是屏蔽指令重排序,这样就保证了多线程安全

这里就不牵扯太多多线程了,毕竟写的是设计模式

3.静态内部类

public class Singleton {

    private static class Holder {
        private static Singleton sl = new Singleton();
    }

    public static Singleton getInstance() {
        Holder holder = new Holder();
        return holder.sl;
    }
}

看到这个写法,你肯定很萌比,这能解决什么问题呢

按需加载:
无论是静态还是非静态内部类都是在第一次使用时才会被加载,外部类不调用getInstance,内部类是不会被加载的

多线程安全:

类加载的时候有一种机制叫做 缓存机制;第一次加载成功之后会被缓存起来,所以基本上实现了和饿汉模式一样的效果

End

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值