单例模式
Posted xmsx
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单例模式相关的知识,希望对你有一定的参考价值。
目录
饿汉式单例
public class Singleton {
private static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
}
饿汉式单例,在类第一次加载的时候,单例就完成了初始化,是线程安全的。
懒汉式单例
public class Singleton {
private static Singleton instance = null;
public static Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
懒汉式单例,运用了延迟加载,在需要的时候进行初始化。
但多线程下有两个问题:
- 可能会得到不同的实例,违背了单例的初衷。
- 可能得到一个尚未初始化完全的对象。
怎样修改懒汉式单例才能保证线程安全性呢?
DCL+ volatile
DCL 即双重检查锁定机制
// 尝试一:锁可以保证线程安全性,但并发的情况下阻塞会导致效率低
public class Singleton {
private static Singleton instance = null;
synchronized public static Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
// 尝试二:缩小同步块的范围,有助于提高效率,但效果微乎其微
public class Singleton {
private static Singleton instance = null;
public static Singleton getInstance() {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
return instance;
}
}
// 尝试三:继续缩小同步块的范围,效率明显提升,但得到的可能不是单例
public class Singleton {
private static Singleton instance = null;
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
instance = new Singleton();
}
}
return instance;
}
}
// 尝试四:DCL,第一次空值检测对提升性能起到了很大的作用,但可能得到一个尚未初始化完全的对象
public class Singleton {
private static Singleton instance = null;
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
// 尝试五:在 DCL 基础上,为变量 instance 加上 voltile 关键字
public class Singleton {
private volatile static Singleton instance = null;
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
voltile 禁止了指令级并行的《重排序》,保证了初始化安全性。
懒汉式单例,使用 DCL + volatile,才具有线程安全性。
静态内部类实现单例模式
public class Singleton {
private static class Holder{
private static Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return Holder.instance;
}
}
调用 getInstance 方法导致 Holder 类被加载,加载过程中初始化了单例。
而类的加载是加锁的,加载完成后才能加载另一个类,因此能够保证单例模式的安全性。
同时具有延时加载的特性。
以上是关于单例模式的主要内容,如果未能解决你的问题,请参考以下文章