单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 在单例类首次加载时就创建单例 为了解决饿汉式单例可能带来的内存浪费的问题,提出了懒汉式单例。懒汉式单例的特点是:单例对象要在被使用时才会初始化。 缺点 既能解决线程安全又能提升程序性能,提出了双重检查锁 利用了内部类的加载方式:外部类初始化的时候内部类不会加载,只要在调用内部类的方法时才会初始化内部类。 但是,上面这种方法就是完美的么?我们先来看一个测试例子 运行结果: 我们通过构造方法的判断和异常,让调用者只能通过getInstance去拿实例 一个对象创建完成,有时需要将对象序列化后写入磁盘,下次使用再从磁盘读取对象并进行反序列化,将其转成内存对象。反序列化后的对象会重新分配内存,即重新创建。如果序列化的对象是单例对象,就会破坏单例 运行结果: 再来看结果: 注册式单例又被称为登记式单例,就是讲每一个实例都登记到某一个地方,使用唯一标识获取单例 枚举法单例模式是《Effective Java》书中推荐的一种单例模式实现写法 前面我们也讲过ThreadLocal,它是单个线程唯一的,天生就是线程安全的 ThreadLocal单例也算是一种特殊的单例模式吧,对ThreadLocal原理感兴趣的可以去看之前的文章深入理解ThreadLocal 一般建议使用饿汉式单例。只有在要明确实现 lazy loading 效果时,才会使用内部类实现的单例模式。如果涉及到反序列化创建对象时,可以尝试使用第枚举方式。如果有其他特殊的需求,可以考虑使用双重检锁方式。
概念
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。常见写法
饿汉式单例
public class HungerSingleton{ private static final HungerSingleton instance =new HungerSingleton(); private HungerSingleton(){} public static HungerSingleton getInstance(){ return instance; } }
缺点
懒汉式单例
线程不安全
public class LazySingleton{ private static LazySingleton instance =null; private LazySingleton(){} public static LazySingleton getInstance(){ if(instance==null){ return new LazySingleton(); } return instance; } }
缺点
线程安全
public class LazySingleton{ private static LazySingleton instance =null; private LazySingleton(){} public static synchronized LazySingleton getInstance(){ if(instance==null){ return new LazySingleton(); } return instance; } }
双重检查锁
class SynchronizedSingleton{ private static volatile SynchronizedSingleton instance =null; private SynchronizedSingleton(){} private static SynchronizedSingleton getInstance(){ if (instance==null){ synchronized (SynchronizedSingleton.class){ if (instance==null){ return new SynchronizedSingleton(); } } } return instance; } }
缺点
内部类实现
是性能最优的且线程安全的一种懒汉式单例写法class LazyInnerClassSingleton{ private LazyInnerClassSingleton(){} public static final LazyInnerClassSingleton getInstance() { return LazyHoder.instance; } //延迟加载 private static class LazyHoder{ private static final LazyInnerClassSingleton instance=new LazyInnerClassSingleton(); } }
反射破坏单例
class LazyInnerClassSingletonTest{ public static void main(String[] args) { try { Class<?>clazz=LazyInnerClassSingleton.class; Constructor c=clazz.getDeclaredConstructor(null); c.setAccessible(true);//强吻 Object o1=c.newInstance(); Object o2=LazyInnerClassSingleton.getInstance(); System.out.println(o1==o2); } catch (Exception e) { e.printStackTrace(); } } }
可以看到,我们通过反射来调用其构造方法,和调用getInstance方法,出现了两个不同的实例,这种情况怎么解决呢?class LazyInnerClassSingleton{ private LazyInnerClassSingleton(){ if(LazyHoder.instance!=null){ throw new RuntimeException("不允许创建多个实例"); } } public static final LazyInnerClassSingleton getInstance() { return LazyHoder.instance; } //延迟加载 private static class LazyHoder{ private static final LazyInnerClassSingleton instance=new LazyInnerClassSingleton(); } }
序列化破坏单例
public class HungerSingleton implements Serializable{ private static final HungerSingleton instance =new HungerSingleton(); private HungerSingleton(){} public static HungerSingleton getInstance(){ return instance; } public static HungerSingleton deepClone(HungerSingleton hs){ HungerSingleton i =null; try { //序列化对象 FileOutputStream fo=new FileOutputStream("HungerSingleton.obj"); ObjectOutputStream os=new ObjectOutputStream(fo); os.writeObject(hs); os.flush(); os.close(); //反序列化对象 FileInputStream fi=new FileInputStream("HungerSingleton.obj"); ObjectInputStream ois=new ObjectInputStream(fi); i=(HungerSingleton)ois.readObject(); ois.close(); } catch (Exception e) { e.printStackTrace(); } return i; } public static void main(String[] args) { HungerSingleton i=HungerSingleton.getInstance(); HungerSingleton ii=deepClone(i); System.out.println(i==ii); } }
很明显,序列化后的对象和手动创建的对象是不一致的,实例化了两次。那么,怎么去解决这个问题呢?很简单,只需要增加readResolve方法就可以了public class HungerSingleton implements Serializable{ private static final HungerSingleton instance =new HungerSingleton(); private HungerSingleton(){} public static HungerSingleton getInstance(){ return instance; } //序列化破坏单例的解决方案: //重写readResolve方法 private Object readResolve(){ return instance; } }
注册式单例
枚举式单例
enum EnumSingleton{ INSTANCE; private Object obj; private Object getObj(){ return obj; } public static EnumSingleton getInstance(){ return INSTANCE; } public static void main(String[] args) { EnumSingleton e1=EnumSingleton.getInstance(); EnumSingleton e2=EnumSingleton.getInstance(); System.out.println(e1==e2); } }
缺点
ThreadLocal单例
class ThreadLocalSingleton{ private ThreadLocalSingleton(){} private static final ThreadLocal<ThreadLocalSingleton> instance=new ThreadLocal<ThreadLocalSingleton>(){ @Override protected ThreadLocalSingleton initialValue() { return new ThreadLocalSingleton(); } }; private static ThreadLocalSingleton getInstance(){ return instance.get(); } }
总结
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算