咕泡学习--各种单例模式及优缺点
一:饿汉式单例模式,优点:线程绝对安全,无锁,效率高。缺点:类加载的时候就初始化,不管用不用,都占用空间。
public class HungrySingleton { //先静态、后动态 //先属性、后方法 //先上后下 private static final HungrySingleton hungrySingleton = new HungrySingleton(); private HungrySingleton(){} public static HungrySingleton getInstance(){ return hungrySingleton; } }
二:懒汉式单例
①简单懒汉式单例,优点:在外部需要使用的时候才进行实例化 缺点:线程不安全
public class LazySimpleSingleton { private LazySimpleSingleton(){} //静态块,公共内存区域 //不能加final,final修饰变量必须直接赋值,或者在静态块赋值。否则报错 private static LazySimpleSingleton lazy = null; public synchronized static LazySimpleSingleton getInstance(){ if(lazy == null){ lazy = new LazySimpleSingleton(); } return lazy; } }
②双重检查懒汉式单例,
public class LazyDoubleCheckSingleton { //volatile 关键字禁止指令重排序,保证线程安全 private volatile static LazyDoubleCheckSingleton lazy = null; private LazyDoubleCheckSingleton(){} public static LazyDoubleCheckSingleton getInstance(){ //第一次检查,减少竞争锁 if(lazy == null){ synchronized (LazyDoubleCheckSingleton.class){ //第二次检查,因为可能会有多个线程一起进入同步块外的 if,如果在同步块内不进行二次检验的话就会生成多个实例 if(lazy == null){ lazy = new LazyDoubleCheckSingleton(); //1.分配内存给这个对象 //2.初始化对象 //3.设置lazy指向刚分配的内存地址 //4.初次访问对象 //因为jvm指令可能会重排序导致2,3可能会赋值错误,所以需要对象加上volatile 关键字 } } } return lazy; } }
③内部类实现单例 优点:完美地屏蔽了饿汉式的内存浪费,和synchronized性能问题 ,史上最牛B的单例模式的实现方式
public class LazyInnerClassSingleton { //默认使用LazyInnerClassGeneral的时候,会先初始化内部类 //如果没使用的话,内部类是不加载的 private LazyInnerClassSingleton(){ if(LazyHolder.LAZY != null){ throw new RuntimeException("不允许创建多个实例"); } } //每一个关键字都不是多余的 //static 是为了使单例的空间共享 //保证这个方法不会被重写,重载 public static final LazyInnerClassSingleton getInstance(){ //在返回结果以前,一定会先加载内部类 return LazyHolder.LAZY; } //默认不加载 private static class LazyHolder{ private static final LazyInnerClassSingleton LAZY = new LazyInnerClassSingleton(); } }
三:注册式单例
①pring中的做法
public class ContainerSingleton { private ContainerSingleton(){} private static Map<String,Object> ioc = new ConcurrentHashMap<String,Object>(); public static Object getInstance(String className){ synchronized (ioc) { if (!ioc.containsKey(className)) { Object obj = null; try { obj = Class.forName(className).newInstance(); ioc.put(className, obj); } catch (Exception e) { e.printStackTrace(); } return obj; } else { return ioc.get(className); } } } }
②枚举
public enum EnumSingleton { INSTANCE; private Object data; public Object getData() { return data; } public void setData(Object data) { this.data = data; } public static EnumSingleton getInstance(){ return INSTANCE; } }
四:序列化实现单例 反序列化时导致单例破坏
public class SeriableSingleton implements Serializable { //序列化就是说把内存中的状态通过转换成字节码的形式 //从而转换一个IO流,写入到其他地方(可以是磁盘、网络IO) //内存中状态给永久保存下来了 //反序列化 //讲已经持久化的字节码内容,转换为IO流 //通过IO流的读取,进而将读取的内容转换为Java对象 //在转换过程中会重新创建对象new public final static SeriableSingleton INSTANCE = new SeriableSingleton(); private SeriableSingleton(){} public static SeriableSingleton getInstance(){ return INSTANCE; } private Object readResolve(){ return INSTANCE; } }
五:序列化实现单例 threadlocal实现单例
public class ThreadLocalSingleton { private static final ThreadLocal<ThreadLocalSingleton> threadLocalInstance = new ThreadLocal<ThreadLocalSingleton>(){ @Override protected ThreadLocalSingleton initialValue() { return new ThreadLocalSingleton(); } }; private ThreadLocalSingleton(){} public static ThreadLocalSingleton getInstance(){ return threadLocalInstance.get(); } }
四:序列化实现单例
浙公网安备 33010602011771号