单例模式
什么是设计模式?
设计模式可以看做为框架或者是围棋中的”棋谱”, 红方当头炮, 黑方马来跳. 根据一些固定的套路下,能保证局势不会吃亏.
在日常的程序设计中, 往往有许多业务场景, 根据这些场景, 大佬们总结出了一些固定的套路. 按照这个套路来实现代码, 也不会吃亏.
什么是单例模式, 保证某类在程序中只有一个实例, 而不会创建多份实例.
单例模式具体的实现方式:可分为”懒汉模式”, ”饿汉模式”.
类加载的同时,创建实例
用private修饰构造方法,使外部类无法调用构造方法创建实例
class singleHunger{
private static singleHunger instance = new singleHunger(); //创建实例
public static singleHungergetInstance(){ //提供方法获取instance
return instance;
}
private singleHunger (){
}
}
类加载时不创建实例, 在调用获取实例的方法时,创建实例
用private修饰构造方法,使外部类无法调用构造方法创建实例
class singleLazy{
public static singleLazy instance = null;
private singleLazy(){}
public static singleLazygetInstance(){
if ( instance == null){
return instance = new singleLazy(); //创建实例
}
return instance;
}
}
在多线程环境中,使用上面的懒汉模式-单线程版实现 ,在实例首次创建时会有线程安全问题.
线程安全问题分析:
两个线程调用singleLazygetInstance()方法获取实例, 如果两个线程的if 判断都为 true, 此时两个线程都分别创建了实例, 两个实例互不相同违背了单例模式的唯一实例的设定.
使用synchronized()进行加锁解决线程安全问题
代码实例:
class singleLazy{
public static singleLazy instance = null;
static Object object = new Object();
private singleLazy(){}
public static singleLazy getInstance(){
synchronized (singleLazy.object) {
if (instance == null) {
return instance = new singleLazy();
}
}
return instance;
}
}
以下代码在加锁的基础上, 做出了进一步改动:
使用双重 if 判定, 降低锁竞争的频率.
给 instance 加上了 volatile.
代码演示:
class singleLazy{
public static singleLazy instance = null;
static Object object = new Object();
private singleLazy(){}
public static singleLazy getInstance(){
if(instance == null){
synchronized (singleLazy.object) {
if (instance == null) {
return instance = new singleLazy();
}
}
}
return instance;
}
}
加锁和解锁的操作是非常影响代码效率的, 饿汉模式只有在首次创建实例的时候会出现线程安全问题, 加入双重if判断可以避免频繁的加锁解锁问题.大大提高了代码执行效率.
引入volatile修饰instance, 可以有效避免”代码可见性”和”指令重排序问题”
可能出现指令重排序问题:
instance = new singleLazy(), 代码指令一共由三个代码命令组成
如果此顺序被优化成 1 3 2 的话 ,就会导致singleLazy的类方法和属性还未被初始化,但instance已不为null了,就会通过if判断条件返回还未初始化完成的instance,当调用instance的属 性跟方法时就会出现异常.
好了本次的学习分享就到这里了,如果本次分享对你有帮助的话,请点一个免费的赞支持一下作者哦.谢谢啦! 我们下次再见