什么是单例模式(上)
Posted 豆豆的杂货铺
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了什么是单例模式(上)相关的知识,希望对你有一定的参考价值。
1什么是单例模式?
单例模式是指在系统运行期间,一个类有且只有一个对象实例对外提供服务,并提供一个全局的访问入口。
2单例模式的应用场景有哪些?
数据库连接池或者线程池。
spring IOC 容器中的 bean 默认是单例模式。
Web 应用的配置对象,一个应用配置文件肯定是全局共享的,所以一般使用单例模式。
3单例模式的关键点
私有构造方法,不可以随便进行 new 操作。
提供全局访问入口,获取单例对象。
4单例模式的写法
饿汉式
public class Singleton {
private static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
private Singleton() { }
}
这段代码没什么好说的,类加载时直接初始化。因为类加载只加载一次,所以不存在线程安全问题。
懒汉式
public class Singleton {
private static Singleton instance = null;
public static Singleton getInstance() {
if(null == instance){
instance = new Singleton();
}
return instance;
}
private Singleton() { }
}
他们的名字很形象,「饿汉式」主动寻找吃的,「懒汉式」等着别人喂。相比「饿汉式」而言,「懒汉式」是在 getInstance 时才去做类的初始化。但是这段代码这里存在一个问题,就是线程安全问题。
假设 getInstance 方法第一次被调用,instance 还是 null,线程 A 与线程 B 同时执行到 if 判断,因为 instance 还是 null,所以两个线程同时通过了 if 判断,执行 new 操作,最终 instance 被实例化两次。
线程安全的单例模式
public class Singleton {
private static Singleton instance = null;
public static Singleton getInstance() {
synchronized (Singleton.class) {
if (null == instance) {
instance = new Singleton();
}
}
return instance;
}
private Singleton() { }
}
为了防止 instance 被实例化多次,所以在 new 操作之前加 synchronized 锁住整个类。这样字就可以保证 new 操作只被执行一次了。为什么是先获取锁在做判空操作呢,你想下,如果先判空在获取锁跟「懒汉式」岂不是没啥区别。但是这段代码也不是完美的,因为只需要第一次执行 new 操作时加锁就可以了,后面就不需要锁了,因为有 if 判空操作。现在的代码每次 getInstance 时都获取锁很影响效率。
兼容效率与线程安全的单例模式
public class Singleton {
private static Singleton instance = null;
public static Singleton getInstance() {
if (null == instance) {
synchronized (Singleton4.class) {
if (null == instance) {
instance = new Singleton();
}
}
}
return instance;
}
private Singleton() {}
}
像这样两次判空的机制叫做双重检测机制。目前来看只有第一次会获取锁,提高了执行效率,而且也不会产生多个实例对象了,完美。但事实真的如此吗?不存在的,这段代码还有一个隐藏的 bug。
假设这样一个场景,两个线程先后进入 getInstance 方法,线程 A 正在构建对象,线程 B 刚进入方法。
单例模式最终版
public class Singleton {
private static volatile Singleton instance = null;
public static Singleton getInstance() {
if (null == instance) {
synchronized (Singleton4.class) {
if (null == instance) {
instance = new Singleton();
}
}
}
return instance;
}
private Singleton() { }
}
什么是 volatile 关键字
被 volatile 修饰的变量禁止指令重排,也就是说 instance = new Singleton() 的执行顺序始终是
如此,在线程 B 看来要么 instance 指向 null,要么初始化完成,不会出现中间状态,也就保证了安全。
其实 volatile 关键字不但可以防止指令重排,也可以保证线程访问的变量值是主内存中的最新值。也就是大家所说的可见性。
--END--
关注「豆豆先生的小屋」,发现更多原创内容。分享技术,畅谈人生,欢迎勾搭!
以上是关于什么是单例模式(上)的主要内容,如果未能解决你的问题,请参考以下文章