饿汉式:在类被加载的时候初始化单例
1.静态变量
类的静态变量会在类被加载时进行初始化,所以饿汉式单例模式是将该类设置为其自身的静态成员变量并进行初始化。该类会在被加载的时候初始化一次,因此是线程安全的。
public class Singleton { private static int value = 0; private static Singleton instance = new Singleton(); private Singleton() { } public static int getValue() { return value; } public static Singleton getInstance() { return instance; } public static synchronized int add() { return ++value; } } // 调用Singleton.getValue()会初始化所有的静态成员变量,instance会被实例化,不是懒加载
2.枚举
自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。不过,JDK1.5之后才可以使用。
public enum Singleton { INSTANCE; public void whateverMethod() { } }
懒汉式:在类第一次被使用的时候初始化
1.静态内部类
当类的静态成员(静态域、构造器、静态方法等)被第一次调用的时候,JVM才会加载该类。静态内部类也是同样,只有当调用静态内部类的静态成员的时候才会加载这个类,因此将单例放入内部静态类可以实现懒加载。
public class Singleton1 { private static int value; private Singleton1() { } public static int getValue() { return value; } public static Singleton1 getInstance() { return SingletonHolder.instance; } private static class SingletonHolder { private static final Singleton1 instance = new Singleton1(); } } //调用Singleton1.getValue() 不会加载SingletonHolder,第一次调用Singleton1.getInstance()时才会加载SingletonHolder并实例化单例,所以内部静态类实现了懒加载,静态变量instance只在类加载的时候初始化一次,所以是线程安全的
使用静态内部类会多初始化一个存储在永久代区域的内部静态类的class对象
2.双重校验锁(double-checked-locking)
将单例类设置为其自身的静态成员变量,为了防止静态变量在类加载的时候初始化,直接将instance设置为空,只有在使用的时候进行初始化。在多线程环境下初始化单例时需要加锁,防止被创建多次。
public class Singleton2 { private static Singleton2 instance = null; private Singleton2() { } public static Singleton2 getInstance() { if (instance == null) { synchronized (Singleton2.class) { if (instance == null) { instance = new Singleton2(); } } } return instance; } }