# 单例模式

# 一、懒汉式-非线程安全

public class Singleton {

    private static Singleton instance = null;

    private Singleton() {
    }

    public static Singleton getInstance() {
        if (null == instance) {
            instance = new Singleton();
        }
        return instance;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 二、饿汉式--性能低

public class Singleton {

    private static final Singleton instance = new Singleton();

    private Singleton() {
    }

    public static Singleton getInstance() {
        return instance;
    }
}
1
2
3
4
5
6
7
8
9
10
11

# 三、懒汉双检锁-线程安全

public class Singleton {

    private volatile static Singleton instance = null;

    private Singleton() {
    }

    public static Singleton getInstance() {
        if (null == instance) {
            synchronized (Singleton.class) {
                if (null == instance) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

1. 为什么需要双重检查

假设两个线程A,B都进入这个方法,判断instance为空,开始争抢Singleton.class锁。当A获取到锁,进行实例的创建,然后释放锁。这时候B等待完毕苏醒也拿到了锁,往下执行就会重复创建对象。

    public static Singleton getInstance() {
        if (null == instance) {
            synchronized (Singleton.class) {
                instance = new Singleton();
            }
        }
        return instance;
    }
1
2
3
4
5
6
7
8

**2. volatile 原因:**防止指令重排序

通过javap -v Demo.class反编译可以看到: instance = new Singleton() 可以拆分为多步:比如

  1. 堆上开辟内存 new

  2. 初始化对象 dup + invokespecial

  3. 指向分配的内存地址 astore_1

    假设 A 线程 执行了1和3,还没执行2,B线程判断 NULL,B 线程就会返回还没初始化的 instance 了,volatile 可以避免指令重排序

# 四、静态内部类-线程安全

public class Singleton {

    private Singleton() {
    }
    
    private static class InnerClass {
        private static Singleton instance = new Singleton();
    }

    public static Singleton getInstance() {
        return InnerClass.instance;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

通过类加载保证线程安全 通过类的加载是线程安全的保证实例的唯一性, 当调用getInstance时触发Singleton类加载,加载过程中会加载InnerClass内部类,加载InnerClass的同时会创建Singleton实例,同时InnerClass是private的,所以保证了唯一性

# 五、枚举

public enum Singleton {
	INSTANCE;
}
1
2
3

# 六、JDK中的单例

public class Runtime {
    private static final Runtime currentRuntime = new Runtime();
    
    private Runtime() {}
    
    public static Runtime getRuntime() {
        return currentRuntime;
    }
}
1
2
3
4
5
6
7
8
9