饿汉式
1 2 3 4 5 6 7 8 9 10 11
| public class Singleton { private static final Singleton instance = new Singleton();
private Singleton() { }
public static Singleton getInstance() { return instance; }
}
|
1 2 3 4 5 6
| public class Main { public static void main(String[] args) { Singleton instance = Singleton.getInstance(); System.out.println(instance); } }
|
懒汉式
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class Singleton { private static Singleton instance;
private Singleton() { }
public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
|
但是这种方法有种缺陷,由于懒汉式在方法中进行初始化,在多线程的环境下,可能会出现问题。
懒汉式-改进
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class Singleton {
private static Singleton instance;
private Singleton() { }
public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { instance = new Singleton(); } } return instance; } }
|
但是这种效率比较低,只能又一个线程能进入同步块,其他的必须要等待
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| 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; } }
|
双重检查可以确保在多线程环境下也能保持单例的唯一性,同时尽可能地减少了同步的开销。
JAVA特有的写法
1 2 3 4 5 6 7 8 9 10 11 12
| public class Singleton {
private Singleton() { } private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.INSTANCE; }
}
|
在Java中,静态内部类在被使用之前是不会被初始化的,这是由类加载器的工作原理决定的。
当程序第一次访问静态内部类 SingletonHolder
时,JVM 会加载 SingletonHolder
类。这个加载过程是延迟的,只有在真正需要使用 SingletonHolder
类时才会触发。所以,即使 Singleton
类被加载了,但是不会导致 SingletonHolder
类被加载,也就不会创建单例对象。