- 懒汉式
- 线程不安全
- 线程安全
- 饿汉式
- DCL(双重校验锁)
- 登记式/静态内部类
单例设计模式:
1.保证一个类只有一个实例 (控制某些共享资源的访问权限 如 数据库或文件)
2.为该实例提供一个全局访问节点
实现步骤:
1.将默认构造方法设置为私有,防止其他对象使用单例类 new运算符
2.新建一个静态构建方法作为构造函数,该函数自动调用私有构造函数来创建对象,并将其保存在一个静态成员变量中。此后 所有对于该函数的调用都将返回这一缓存对象
懒汉式(线程不安全)
public class Singleton {
`private static Singleton instance;`
`private Singleton (){}`
`public static Singleton getInstance() {`
`if (instance == null) {`
`instance = new Singleton();`
`}`
`return instance;`
`}`
}
懒汉式(线程安全) 说真正用到它的时候才去创建实例 synchronized锁的粒度太大
public class Singleton {
`private static Singleton instance;`
`private Singleton (){}`
`public static synchronized Singleton getInstance() {`
`if (instance == null) {`
`instance = new Singleton();`
`}`
`return instance;`
`}`
三、饿汉式(程序刚启动时就创建了实例)
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
四、DCL(双重校验锁)
public class Singleton {
private static Singleton singleton = null;
private Singleton(){}
public static Singleton getInstance(){
/*
一堆业务处理代码
*/
if(null == singleton){
synchronized(Singleton.class){//锁粒度变小
if(null == singleton){//DCL
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
singleton = new Singleton();
}
}
}
return singleton;
}
public static void main(String[] args) {
for (int i=0;i<1000;i++){
new Thread(()-> System.out.println(Singleton.getInstance().hashCode())).start();
}
}
}
通过在第10行又加了一层if判断,也就是所谓的Double Check Lock。也就是说即便拿到锁了,也得去作一步判断,如果这时判断对像不为空,那么就不用再创建对象,直接返回就可以了,很好的解决了“改进2”中的问题。但这里第8行是不是可以去了,我个人觉得都行,保留第8行的话,是为了提升效率,因为如果去了,每个线程过来就直接抢锁,抢锁本身就会影响效率,而if判断就几ns,且大部分线程是不需要抢锁的,所以最好保留。 到这DCL 单例的原理就介绍完了,但是还是有一个问题。就是需要考虑指令重排序的问题,因此得加入volatile来禁止指令重排序。继续分析代码,为了分析方便这里将Singleton代码简化
---
单例模式使用DCL(双重检验锁的)的原理:
单例模式 有饿汉式和懒汉式,
饿汉式在程序刚启动就创建实例,虽然线程安全,但是比较浪费资源, 懒汉式在 在需要的时候才会去创建实例,但是在多线程并发的情况下存在线程不安全的问题,
优化1:是加synchronize关键字,但是synchronize关键字直接加在放上下粒度太大。
优化2:使用 synchronize(Singleton.class){try{}catch()} 来减少锁的粒度,但是并发就会又存在问题 当线程1在准备抢锁的时候可能会被阻塞(如时间片到),这时候线程二 上cpu运行,顺利拿到锁并结束运行释放锁。线程1 恢复,拿到锁吗,运行结束。造成了的线程不安全.
优化3: 尽管某一个线程抢到了锁,也要判断当前 是否已存在实例化的对象,存在了就不在创建,不存在在去实例化。 优化4:就是需要考虑指令重排序的问题,因此得加入volatile来禁止指令重排序
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。