博客
关于我
Java中的单例模式
阅读量:580 次
发布时间:2019-03-11

本文共 3028 字,大约阅读时间需要 10 分钟。

单例模式:饿汉式与懒汉式的比较

单例模式是一种常用的设计模式,用于确保一个类在程序运行期间只创建一个实例。在实际开发中,单例模式广泛应用于资源管理、缓存机制等场景。以下将从饿汉式和DCL懒汉式两种实现方式入手,详细分析其优缺点。

饿汉式单例模式

饿汉式单例模式的特点是“先创建再用”,其实现方式非常直接且简单。以下是典型代码示例:

package com.chao.single;public class Hungry {    private byte[] data1 = new byte[1024*1024];    private byte[] data2 = new byte[1024*1024];    private byte[] data3 = new byte[1024*1024];    private byte[] data4 = new byte[1024*1024];        private Hungry() {    }        private final static Hungry HUNGRY = new Hungry();        public static Hungry getInstance() {        return HUNGRY;    }}

优点:

  • 实现简单,易于理解。
  • 内存中只保留一个实例,节省内存空间。
  • 适用于对内存占用要求较高的场景。

缺点:

  • 在对象初始化时就分配内存,可能导致内存浪费。
  • 如果对象无法被销毁,可能导致内存泄漏。

DCL懒汉式单例模式

DCL懒汉式单例模式的特点是“先用后创建”,通过双重锁机制确保单例的初始化。其实现方式如下:

package com.chao.single;import java.lang.reflect.Constructor;import java.lang.reflect.Field;public class LazyMan {    private static boolean chao = false;    private LazyMan() {        synchronized (LazyMan.class) {            if (chao == false) {                chao = true;            } else {                throw new RuntimeException("不要试图使用反射破坏异常");            }        }    }        private volatile static LazyMan lazyMan;        public static LazyMan getInstance() {        if (lazyMan == null) {            synchronized (LazyMan.class) {                if (lazyMan == null) {                    lazyMan = new LazyMan();                }            }        }        return lazyMan;    }}

优点:

  • 内存占用较低,延迟加载机制减少内存预先分配。
  • 适用于内存资源有限或对象创建频繁的场景。

缺点:

  • 在高并发场景下可能导致性能问题。
  • 双重锁机制增加了额外的同步开销。
  • 单例对象在某些情况下可能无法被销毁,导致内存泄漏。

静态内部类单例模式

静态内部类单例模式通过静态嵌套类实现单例模式,代码结构清晰且易于理解。其实现方式如下:

package com.chao.single;public class Holder {    private Holder() {    }        public static Holder getInstance() {        return InnerClass.HOLDER;    }        public static class InnerClass {        private static final Holder HOLDER = new Holder();    }}

优点:

  • 内部类与外部类的关系清晰,逻辑分离明确。
  • 利用Java的静态嵌套机制,实现了单例模式。
  • 提供了较高的内存安全性。

缺点:

  • 类结构较为复杂,初次理解可能需要时间。
  • 在某些反射攻击下可能存在安全隐患。

单例模式的反射攻击

反射攻击是对单例模式的一种常见测试,验证单例模式的健壮性。以下是一个反射攻击的示例:

public class Test {    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {        EnumSingle instance1 = EnumSingle.INSTANCE;        Constructor declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class, int.class);        declaredConstructor.setAccessible(true);        EnumSingle instance2 = declaredConstructor.newInstance();        System.out.println(instance1);        System.out.println(instance2);    }}

防御措施:

  • 使用私有构造器并设置Accessible属性。
  • 在构造器中添加异常处理,防止反射攻击。
  • 在单例类中添加反射保护机制。

枚举单例模式

枚举类型在Java中本身就是单例的概念。通过枚举来实现单例模式,其优雅之处在于无需手动管理单例实例。以下是一个枚举单例的实现示例:

package com.chao.single;import java.lang.reflect.Constructor;public enum EnumSingle {    INSTANCE;        public EnumSingle getInstance() {        return INSTANCE;    }}

优点:

  • 枚举类型天然支持单例模式。
  • 编译后不可变,提高运行时安全性。
  • 易于管理和理解。

缺点:

  • 枚举常量无法改变,灵活性较低。
  • 在反射攻击下可能存在安全隐患。

总结

单例模式通过控制对象的创建次数,保障了内存资源的高效利用。在实际开发中,选择合适的单例模式需要根据具体需求进行权衡。饿汉式和懒汉式各有优劣,静态内部类和枚举方式则提供了不同的实现思路。无论选择哪种方式,理解其内部机制和潜在问题都是至关重要的。

转载地址:http://igrvz.baihongyu.com/

你可能感兴趣的文章
Pandas数据分析的环境准备
查看>>
Pandas数据可视化怎么做?用实战案例告诉你!
查看>>
Pandas数据处理与分析教程:从基础到实战
查看>>
Pandas数据结构之DataFrame常见操作
查看>>
pandas整合多份csv文件
查看>>
pandas某一列转数组list
查看>>
Pandas模块,我觉得掌握这些就够用了!
查看>>
Pandas玩转文本处理!
查看>>
SpringBoot 整合 Mybatis Plus 实现基本CRUD功能
查看>>
pandas的to_sql方法中使用if_exists=‘replace‘
查看>>
Springboot ppt转pdf——aspose方式
查看>>
pandas读取parquet报错
查看>>
pandas读取数据用来深度学习
查看>>
Pandas进阶大神!从0到100你只差这篇文章!
查看>>
spring5-介绍Spring框架
查看>>
pandas,python - 如何在时间序列中选择特定时间
查看>>
Spring 框架之 AOP 原理深度剖析
查看>>
Pandas:如何按列元素的组合分组,以指示基于不同列的值的同现?
查看>>
Pandas:将一列与数据帧的所有其他列进行比较
查看>>
PANDA:基于多列对数据表的行运行计算,并将输出存储在新列中
查看>>