前言:单例模式
懒汉式单例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class Singleton { private Singleton () {} private static Singleton instance = null ; public static Singleton getInstance () { if (instance == null ){ instance = new Singleton(); } return instance; } }
加入synchronized
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class Singleton { private Singleton () {} private static Singleton instance = null ; public static synchronized 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 17 18 public class Singleton { private Singleton () {} private static volatile Singleton instance = null ; public static Singleton getInstance () { if (instance == null ){ synchronized (Singleton.class ) { if (instance == null ){ instance = new Singleton(); } } } return instance; } }
注意,双重检查锁定要volatile,因为Java中看似顺序的代码到JVM中会指令重排,Java指令中创建对象和赋值操作是分开进行的,也就是说instance = new Singleton();语句是分两步执行的。但是JVM并不保证这两个操作的先后顺序,也就是说有可能JVM会为新的Singleton实例分配空间,然后直接赋值给instance成员,然后再去初始化这个Singleton实例。这样就使出错成为了可能
容器实现单例模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class Singleton { private static Map<String, Object> singletonMap = new HashMap<String, Object>(); private Singleton () { } public static void registerSingleton (String key, Object instance) { if (!singletonMap.containsKey(key)) { singletonMap.put(key, instance); } } public static Object getSingleton (String key) { return singletonMap.get(key); } }
饿汉式单例 1 2 3 4 5 6 7 8 9 10 11 public class Singleton { private Singleton () {} private static Singleton instance = new Singleton(); public static Singleton getInstance () { return instance; } }
饿汉式单例类线程安全控制烦琐,而且性能受影响
饿汉式单例类不能实现延迟加载,不管将来用不用始终占据内存
延迟加载单例模式(静态内部类) 基于饿汉式单例,静态变量在类加载时初始化,而静态内部类在外部类调用时才初始化,因此可使用静态内部类实现延迟加载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class Singleton { private Singleton () { } private static class HolderClass { private final static Singleton instance = new Singleton(); } public static Singleton getInstance () { return HolderClass.instance; } }