深度解析单例模式
一、概述
1.1 特点
- 单例类。只有一个实例对象;
- 该单例对象必须由单例类自行创建
- 单例类对外提供一个访问该单例的全局访问点。
1.2 优缺点
优点:
(图片来源网络,侵删)
- 保证内存里只有一个实例,减少了内存的开销。
- 可以避免对资源的多重占用
缺点:
- 没有接口,扩展困难。违背开闭原则。
- 不利于代码调试。调试过程中,如果单例代码没有执行完,不能创建一个对象
1.3 应用场景
- 频繁创建类,使用单例可以降低系统的内存压力,减少GC。
- 全局信息类。利用一个类记录网站的访问次数,不希望有的访问被记录在对象A上,有的记录在对象B上。
二、八种经典实现方式
2.1 饿汉式
代码实现:
public class Hungry { private Hungry(){}; // 1. 静态变量 // private static Hungry hungry = new Hungry(); // 2. 静态代码块 private final static Hungry hungry; static { hungry = new Hungry(); } public static Hungry getInstance() { return hungry; } }
优点: 类加载时,就把实例初始化。
缺点: 浪费内存空间。
2.2 懒汉式
代码实现:
// 1. 线程不安全 // 2. 线程安全,synchronized修饰方法 // 3. 线程安全,synchronized代码块修饰 public class Lazy { private Lazy(){ } // 1. 多线程不安全 private static Lazy lazy = null; public Lazy getInstance() { if (lazy == null) { lazy = new Lazy(); } return lazy; } // 2. 线程安全,synchronized修饰方法。多线程无法并行处理,效率低下 public synchronized Lazy getInstance() { if (lazy == null) { lazy = new Lazy(); } return lazy; } // 3. 线程安全,synchronized代码块修饰. 产生多个实例,即多个线程都通过lazy==null的判断 public static Lazy getInstance(){ if (lazy == null) { synchronized (Lazy.class){ lazy = new Lazy(); } } return lazy; }
适用场景: 如果程序一开始要加载的资源太多,可以使用懒加载。
2.3 双重检查方式
代码实现:
// 1. 双重检测1:线程安全,效率较高,延迟加载; // 但存在指令重排,即创建对象需要3个步骤,3个步骤之间可能会重排,导致空指针 // 异常 // 2. 双重检测2:利用volatile修饰的变量;volatile可以防止指令重排 public class DoubleCheck { private DoubleCheck(){ } // 1. 双重检测1 // private static DoubleCheck doubleCheck; // 2. 双重检测2 private volatile static DoubleCheck doubleCheck; public static DoubleCheck getInstance() { if (doubleCheck == null) { synchronized (DoubleCheck.class) { if (doubleCheck == null) { doubleCheck = new DoubleCheck(); } } } return doubleCheck; } } 优点:线程安全;延迟加载;效率较高
2.4 静态内部类方式
public class Inner { private Inner(){ } public static Inner getInstance() { return InnerClass.inner; } private static class InnerClass{ private static final Inner inner = new Inner(); } } 静态内部类方式在Inner类被装载时并不会立即实例化,而是在需要实例化时,调用getInstance方法,才会装载 InnerClass类,从而完成Singleton的实例化。 类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮助我们保证了线程的安全性,在类进行初始化 时,别的线程是无法进入的。 【优点】:避免了线程不安全,延迟加载,效率高
2.5 枚举类方式
// 最安全 public enum EnumSingle { INSTANCE; public static EnumSingle getInstance(){ return INSTANCE; } } 优点: 1. 写法简单 2. 线程安全 3. 避免反序列化破坏单例
免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!