Java中的单例模式
一、饿汉式
public class HungerySingleton { //ClassLoader 类加载时立即实例化对象,仅实例化一次,线程安全的 private static HungerySingleton hungerySingleton = new HungerySingleton(); public static HungerySingleton getInstance(){ return hungerySingleton; } //利用线程输出(后面就不写了哈) public static void main(String[]args){ for(int i=0;i<20;i++){ Thread thread =new Thread() { @Override public void run() { HungerySingleton hungerySingleton = HungerySingleton.getInstance(); System.out.println(hungerySingleton); } }; thread.start(); } } }
优点:仅实例化一次,线程是安全的。获取实例的速度快
缺点:类加载时立即实例化对象,可能实例化的对象不被使用,造成内存的浪费。
二、懒汉式
public class HoonSingleton { //不能保证实例对象的唯一性 private static HoonSingleton hoonSingleton = null; public static HoonSingleton getInstance(){ if(hoonSingleton==null){ hoonSingleton = new HoonSingleton(); } return hoonSingleton; } }
优点:获取实例时才进行实例的初始化,节省系统资源
缺点:1、如果获取实例时,初始化的工作量较多,加载速度会变慢,影响系统系能
2、每次获取实例都要进行非空检查,系统开销大
3、非线程安全。注意红色代码标记,当多个线程同时getInstance()时,可能hoonSingleton实例化未完成,hoonSingleton==null判断均为true,造成对象重复实例化。
三、双重检查锁 DCL(double-checked locking)+ volatile
public class HoonSingleton { private static volatile HoonSingleton hoonSingleton = null; // 使用sync同步HoonSingleton.class 两次判断hoonSingleton是否为null 避免并发导致hoonSingleton被重新实例化 // 并没有对整个方法使用sync,锁的粒度变小了,实现了实例对象的唯一性 public static HoonSingleton getInstance(){ if(hoonSingleton==null){ synchronized (HoonSingleton.class) { if(hoonSingleton==null) { hoonSingleton = new DCL(); } } } return hoonSingleton; }
优点:1、线程安全。注意加粗标记,进行双重检查,保证只在实例未初始化前进行同步,效率高。
2、对hoonSingleton使用volatile修饰符,避免实例化过程中产生的重排序。避免NPE抛出。
缺点:实例非空判断,耗费一定资源
四、Holder方式 广泛使用的一种单例模式
//声明类的时候、成员变量中不声明实例变量,而是放到内部静态类中 public class HolderDemo { private static class Holder{ private static HolderDemo instance = new HolderDemo(); } public static HolderDemo getInstance(){ return Holder.instance; } }
优点:1、内部类只有在外部类被调用才加载,从而实现了延迟加载
2、线程安全。且不用加锁。
五、使用枚举的单例模式,本质上和饿汉模式没有任何区别,只是采用Enum实现的更巧妙了
public enum EnumSingleton { //枚举类型,在加载的时候实例化。 INSTANCE; public static EnumSingleton getInstance(){ return INSTANCE; } }
优点:仅实例化一次,线程是安全的。获取实例的速度快
缺点:类加载时立即实例化对象,可能实例化的对象不被使用,造成内存的浪费。
六、枚举和懒汉模式相结合
public class EnumSingletonDemo { private enum EnumHolder{ INSTANCE; private static EnumSingletonDemo instance=null; private EnumSingletonDemo getInstance(){ if(instance ==null) { instance = new EnumSingletonDemo(); } return instance; } } //实现懒加载 public static EnumSingletonDemo getInstance(){ return EnumHolder.INSTANCE.getInstance(); }
优点:1、线程安全。且不用加锁。
2、实现了懒加载
缺点:仍然需要实例非空判断,耗费一定资源