Java:java学习笔记之Java单例模式的简单理解和使用
Posted JMW1407
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java:java学习笔记之Java单例模式的简单理解和使用相关的知识,希望对你有一定的参考价值。
Java单例模式的简单理解和使用
Java单例模式
1、饿汉式单例的实现如下:
//饿汉式实现
public class SingleB
private static final SingleB INSTANCE = new SingleB();
private SingleB()
public static SingleB getInstance()
return INSTANCE;
2、懒汉式终极版本:volatile
// Version 4
public class Single4
private static volatile Single4 instance;
private Single4()
public static Single4 getInstance()
if (instance == null)
synchronized (Single4.class)
if (instance == null)
instance = new Single4();
return instance;
主要在于singleton = new Singleton()这句,这并非是一个原子操作,事实上在 JVM 中这句话大概做了下面 3 件事情:
- 1、给 singleton 分配内存
- 2、调用 Singleton 的构造函数来初始化成员变量,形成实例
- 3、将singleton对象指向分配的内存空间(执行完这步 singleton才是非 null 了)
但是在 JVM 的即时编译器中存在指令重排序的优化。也就是说上面的第二步和第三步的顺序是不能保证的,最终的执行顺序可能是 1-2-3
也可能是 1-3-2
:
- 如果是后者,则在 3 执行完毕、2 未执行之前,被线程二抢占了,这时
instance 已经是非 null了(但却没有初始化)
,所以线程二会直接返回 instance,然后使用,然后顺理成章地报错。
再稍微解释一下,就是说,由于有一个『instance已经不为null但是仍没有完成初始化』的中间状态
,而这个时候,如果有其他线程刚好运行到第一层if (instance == null)这里,这里读取到的instance已经不为null了,所以就直接把这个中间状态的instance拿去用了,就会产生问题。
- 这里的关键在于——线程T1对instance的
写操作没有完成
,线程T2就执行了读操作
。
volatile关键字的作用
volatile关键字的一个作用是禁止指令重排
,把instance声明为volatile之后,对它的写操作就会有一个内存屏障
,这样,在它的赋值完成之前,就不用会调用读操作。
- 注意:
volatile
阻止的不singleton = newSingleton()
这句话内部[1-2-3]
的指令重排,而是保证了在一个写操作([1-2-3])
完成之前,不会调用读操作(if(instance == null))
。
3、Effective Java 1 —— 静态内部类
// Effective Java 第一版推荐写法
public class Singleton
private static class SingletonHolder
private static final Singleton INSTANCE = new Singleton();
private Singleton ()
public static final Singleton getInstance()
return SingletonHolder.INSTANCE;
这种写法非常巧妙:
- 对于内部类
SingletonHolder
,它是一个饿汉式的单例实现,在SingletonHolder
初始化的时候会由ClassLoader
来保证同步,使INSTANCE
是一个真·单例。 - 同时,由于
SingletonHolder
是一个内部类,只在外部类的Singleton
的getInstance
()中被使用,所以它被加载的时机也就是在getInstance()方法第一次被调用的时候。 - 它利用了
ClassLoader
来保证了同步,同时又能让开发者控制类加载的时机。从内部看是一个饿汉式的单例,但是从外部看来,又的确是懒汉式的实现。
4、5.2 Effective Java 2 —— 枚举
// Effective Java 第二版推荐写法
public enum SingleInstance
INSTANCE;
public void fun1()
// do something
// 使用
SingleInstance.INSTANCE.fun1();
参考
以上是关于Java:java学习笔记之Java单例模式的简单理解和使用的主要内容,如果未能解决你的问题,请参考以下文章