1.饿汉式
public class EagerSingleton { private static EagerSingleton eagerSingleton = new EagerSingleton(); private EagerSingleton(){} public static EagerSingleton getInstance(){ return eagerSingleton; }
- private 私有化构造函数,保证其他类不能实例化该类。
- 静态实例只在类加载的时候创建一次,不会多次创建线程,避免了多线程的情况。
- 缺点也是显而易见的,类加载之后就会创建实例,在实例未起到调用的时候容易造成内存浪费,影响性能,懒汉式完美避免这个缺点。
2.懒汉式 (线程不安全)
public class LazySingleton { private static LazySingleton lazySingleton; private LazySingleton(){} public static LazySingleton newInstance(){ if(lazySingleton == null){ /* try{Thread.sleep(2000); }catch (Exception e){}*/ lazySingleton = new LazySingleton(); } return lazySingleton; } }
- 该模式下在需要的时候才去创建实例对象,避免了内存浪费的问题。
- 多线程情况下会造成对象多次创建的情况,破坏单例特性,可放开上述代码模拟多线程调用情况下对象多次创建问题。
3 .懒汉式 (线程安全,synchronized )
public class LazySignletonSafe { private static LazySignletonSafe lazySignletonSafe; private LazySignletonSafe(){} public static synchronized LazySignletonSafe getInstance(){ if (lazySignletonSafe == null){ lazySignletonSafe = new LazySignletonSafe(); } return lazySignletonSafe; } }
- 优点同上,同步方法避免了多线程调用多次创建实例的情况。由于synchronized 锁的特性,线程是安全的,但是会造成多线程情况下效率低的问题。
4 .懒汉式 (线程安全,双重检测)
public class LazySignletonDoubleCheck { //volatile避免了指令重排序问题和保证了可见性问题 private static volatile LazySignletonDoubleCheck lazySignletonDoubleCheck; private LazySignletonDoubleCheck(){} public static LazySignletonDoubleCheck getInstance(){ //第一个if判断对象为空的时候才去创建 if (lazySignletonDoubleCheck == null){ //第二个if避免了多线程情况下多次创建对象(在对象为空时,多个线程通过了第一个if判断,在不存在第二个if的情况,将会直接创建对象 synchronized (LazySignletonDoubleCheck.class){ if(lazySignletonDoubleCheck == null){ lazySignletonDoubleCheck = new LazySignletonDoubleCheck(); } } } return lazySignletonDoubleCheck; } }
5.静态内部类 实现单例
- 优点同上,synchronized锁只同步对象创建的代码在保证了线程安全的同时提高了多线程调用情况下的效率问题。而且第一次if判断也避免了所有线程争抢同步锁的情况。
public class InnerSignleton { private InnerSignleton(){} public static InnerSignleton getInstance() { return SingletonUtils.innerSignleton; } private static class SingletonUtils { private static InnerSignleton innerSignleton = new InnerSignleton(); } public static void main(String[] args) { InnerSignleton instance1 = InnerSignleton.getInstance(); InnerSignleton instance2 = InnerSignleton.getInstance(); System.out.println(instance1 == instance2); } }
- 由于静态属性加载只加载一次的问题。静态内部类完美避免内存浪费和多线程问题。
6.枚举实现单例
public enum EnumSignleton { INSTANCE; // 枚举能够绝对有效的防止实例化多次,和防止反射和序列化破解 public void add() { System.out.println("add方法..."); } public static void main(String[] args) throws Exception { EnumSignleton instance1 = EnumSignleton.INSTANCE; EnumSignleton instance2 = EnumSignleton.INSTANCE; System.out.println(instance1 == instance2); Constructor<EnumSignleton> declaredConstructor = EnumSignleton.class.getDeclaredConstructor(); declaredConstructor.setAccessible(true); EnumSignleton v3 = declaredConstructor.newInstance(); System.out.println(v3==instance1); }
- 枚举能够绝对有效的防止实例化多次,和防止反射和序列化破解
7.使用容器管理
public class SingletonManager { private static Map<String, Object> objMap = new HashMap<String, Object>(); public static void registerService(String key, Object instance) { if (!objMap.containsKey(key)) { objMap.put(key, instance); } } public static Object getService(String key) { { return objMap.get(key); } } }
-
这种使用SingletonManager 将多种单例类统一管理,在使用时根据key获取对象对应类型的对象。这种方式使得我们可以管理多种类型的单例,并且在使用时可以通过统一的接口进行获取操作,降低了用户的使用成本,也对用户隐藏了具体实现,降低了耦合度。