单例模式有如下实现方式:
- package com.zzj.pattern.singleton;
- public class Singleton {
- private static Singleton instance;
- private Singleton() {
- }
- public static Singleton getInstance() {
- if (instance == null) {
- instance = new Singleton();
- }
- return instance;
- }
- }
这种方式称为延迟初始化,但是在多线程的情况下会失效,于是使用同步锁,给getInstance() 方法加锁:
- public static synchronized Singleton getInstance() {
- if (instance == null) {
- instance = new Singleton();
- }
- return instance;
- }
- public static Singleton getInstance() {
- if (instance == null) {
- synchronized (Singleton.class) {
- if (instance == null) {
- instance = new Singleton();
- }
- }
- }
- return instance;
- }
指令重排序是为了优化指令,提高程序运行效率。指令重排序包括编译器重排序和运行时重排序。JVM规范规定,指令重排序可以在不影响单线程程序执行结果前提下进行。例如 instance = new Singleton() 可分解为如下伪代码:
- memory = allocate(); //1:分配对象的内存空间
- ctorInstance(memory); //2:初始化对象
- instance = memory; //3:设置instance指向刚分配的内存地址
- memory = allocate(); //1:分配对象的内存空间
- instance = memory; //3:设置instance指向刚分配的内存地址
- //注意,此时对象还没有被初始化!
- ctorInstance(memory); //2:初始化对象
鉴于DCL的缺陷,便有了修订版:
- public static Singleton getInstance() {
- if (instance == null) {
- synchronized (Singleton.class) {
- Singleton temp = instance;
- if (temp == null) {
- synchronized (Singleton.class) {
- temp = new Singleton();
- }
- instance = temp;
- }
- }
- }
- return instance;
- }
在JDK1.5之后,可以使用volatile变量禁止指令重排序,让DCL生效:
- package com.zzj.pattern.singleton;
- public class Singleton {
- private static volatile Singleton instance;
- private Singleton() {
- }
- public static Singleton getInstance() {
- if (instance == null) {
- synchronized (Singleton.class) {
- if (instance == null) {
- instance = new Singleton();
- }
- }
- }
- return instance;
- }
- }
读volatile:每当子线程某一语句要用到volatile变量时,都会从主线程重新拷贝一份,这样就保证子线程的会跟主线程的一致。
写volatile: 每当子线程某一语句要写volatile变量时,都会在写完后同步到主线程去,这样就保证主线程的变量及时更新。
volatile的另一个语义是保证变量修改的可见性。
单例模式还有如下实现方式:
- package com.zzj.pattern.singleton;
- public class Singleton {
- private static class InstanceHolder {
- public static Singleton instance = new Singleton();
- }
- private Singleton() {
- }
- public static Singleton getInstance() {
- return InstanceHolder.instance;
- }
- }
至此,正确的单例模式有三种实现方式:
1.提前初始化。
- package com.zzj.pattern.singleton;
- public class Singleton {
- private static Singleton instance = new Singleton();
- private Singleton() {
- }
- public static Singleton getInstance() {
- return instance;
- }
- }
3.延迟初始化占位类模式。
转载自:双重检查锁定(double-checked locking)与单例模式