Java单例模式

简介: Java单例模式

单例模式

基本介绍

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一,提供了一种创建对象的最佳方式

在一个程序当中 一个类只创建一个对象 就是单例模式

单例设计模式分类两种:

  • 饿汉式:类加载就会导致该单实例对象被创建 ---》 悲观 锁
    有求必应 添狗
  • 懒汉式:类加载不会导致该单实例对象被创建,而是首次使用该对象时才会创建 --》 乐观锁
    我找了个对象 我无所谓

饿汉式

饿汉式在类加载的过程导致该单实例对象被创建,虚拟机会保证类加载的线程安全,但是如果只是为了加载该类不需要实例,则会造成内存的浪费

  • 静态变量的方式:
 public final class Singleton {
     // 私有构造方法
     private Singleton() {}
     // 在成员位置创建该类的对象
     private static final Singleton instance = new Singleton();
     // 对外提供静态方法获取该对象
     public static Singleton getInstance() {
         return instance;
     }
     1次来创建了一个对象    2次来把第一次的对象销毁   在创建一个对象     3 接着销毁 接着创建
     
     // 解决序列化问题
     protected Object readResolve() {
         return INSTANCE;
     }
 }
  • 加 final 修饰,所以不会被子类继承,防止子类中不适当的行为覆盖父类的方法,破坏了单例
  • 防止反序列化破坏单例的方式:
  • 对单例声明 transient,然后实现 readObject(ObjectInputStream in) 方法,复用原来的单例
    条件:访问权限为 private/protected、返回值必须是 Object、异常可以不抛
  • 实现 readResolve() 方法,当 JVM 从内存中反序列化地组装一个新对象,就会自动调用 readResolve 方法返回原来单例
  • 构造方法设置为私有,防止其他类无限创建对象,但是不能防止反射破坏
  • 静态变量初始化在类加载时完成,由 JVM 保证线程安全,能保证单例对象创建时的安全
  • 提供静态方法而不是直接将 INSTANCE 设置为 public,体现了更好的封装性、提供泛型支持、可以改进成懒汉单例设计
  • 静态代码块的方式:
 public class Singleton {
     // 私有构造方法
     private Singleton() {}
     
     // 在成员位置创建该类的对象
     private static Singleton instance;
     static {
         instance = new Singleton();
     }
     
     // 对外提供静态方法获取该对象
     public static Singleton getInstance() {
         return instance;
     }
 }

枚举方式:枚举类型是所用单例实现中唯一一种不会被破坏的单例实现模式

 public enum Singleton {
     INSTANCE;
     public void doSomething() {
         System.out.println("doSomething");
     }
 }
 public static void main(String[] args) {
     Singleton.INSTANCE.doSomething();
 }
  • 问题1:枚举单例是如何限制实例个数的?每个枚举项都是一个实例,是一个静态成员变量
  • 问题2:枚举单例在创建时是否有并发问题?否
  • 问题3:枚举单例能否被反射破坏单例?否,反射创建对象时判断是枚举类型就直接抛出异常
  • 问题4:枚举单例能否被反序列化破坏单例?否
  • 问题5:枚举单例属于懒汉式还是饿汉式?饿汉式
  • 问题6:枚举单例如果希望加入一些单例创建时的初始化逻辑该如何做?添加构造方法

反编译结果:

 public final class Singleton extends java.lang.Enum<Singleton> { // Enum实现序列化接口
     public static final Singleton INSTANCE = new Singleton();
 }

懒汉式 乐观

  • 线程不安全
 public class Singleton {
     // 私有构造方法
     private Singleton() {}
 ​
     // 在成员位置创建该类的对象
     private static Singleton instance;
     
     1 来 创建一个对象    2 判断你现在是不是有对象   3 直接返回你原本的对象
 ​
     // 对外提供静态方法获取该对象
     public static Singleton getInstance() {
         if(instance == null) {
             // 多线程环境,会出现线程安全问题,可能多个线程同时进入这里
             instance = new Singleton();
         }
         return instance;
     }
 }

双端检锁机制

在多线程的情况下,可能会出现空指针问题,出现问题的原因是 JVM 在实例化对象的时候会进行优化和指令重排序操作,所以需要使用 volatile 关键字

 public class Singleton { 
     // 私有构造方法
     private Singleton() {}
     private static volatile Singleton instance;
 ​
     // 对外提供静态方法获取该对象
     public static Singleton getInstance() {
         // 第一次判断,如果instance不为null,不进入抢锁阶段,直接返回实例
         if(instance == null) {
             synchronized (Singleton.class) {
                 // 抢到锁之后再次判断是否为null
                 if(instance == null) {
                     instance = new Singleton();
                 }
             }
         }
         return instance;
     }
 }

静态内部类方式

 public class Singleton {
     // 私有构造方法
     private Singleton() {}
 ​
     private static class SingletonHolder {
         private static final Singleton INSTANCE = new Singleton();
     }
 ​
     // 对外提供静态方法获取该对象
     public static Singleton getInstance() {
         return SingletonHolder.INSTANCE;
     }
 }
  • 内部类属于懒汉式,类加载本身就是懒惰的,首次调用时加载,然后对单例进行初始化
    类加载的时候方法不会被调用,所以不会触发 getInstance 方法调用 invokestatic 指令对内部类进行加载;加载的时候字节码常量池会被加入类的运行时常量池,解析工作是将常量池中的符号引用解析成直接引用,但是解析过程不一定非得在类加载时完成,可以延迟到运行时进行,所以静态内部类实现单例会延迟加载
  • 没有线程安全问题,静态变量初始化在类加载时完成,由 JVM 保证线程安全


目录
相关文章
|
3月前
|
设计模式 安全 Java
Java编程中的单例模式深入剖析
【10月更文挑战第21天】在Java的世界里,单例模式是设计模式中一个常见而又强大的存在。它确保了一个类只有一个实例,并提供一个全局访问点。本文将深入探讨如何正确实现单例模式,包括常见的实现方式、优缺点分析以及最佳实践,同时也会通过实际代码示例来加深理解。无论你是Java新手还是资深开发者,这篇文章都将为你提供宝贵的见解和技巧。
107 65
|
2月前
|
设计模式 Java 数据库连接
Java编程中的设计模式:单例模式的深度剖析
【10月更文挑战第41天】本文深入探讨了Java中广泛使用的单例设计模式,旨在通过简明扼要的语言和实际示例,帮助读者理解其核心原理和应用。文章将介绍单例模式的重要性、实现方式以及在实际应用中如何优雅地处理多线程问题。
40 4
|
2月前
|
设计模式 安全 Java
Java编程中的单例模式:理解与实践
【10月更文挑战第31天】在Java的世界里,单例模式是一种优雅的解决方案,它确保一个类只有一个实例,并提供一个全局访问点。本文将深入探讨单例模式的实现方式、使用场景及其优缺点,同时提供代码示例以加深理解。无论你是Java新手还是有经验的开发者,掌握单例模式都将是你技能库中的宝贵财富。
58 2
|
2月前
|
设计模式 安全 Java
Java编程中的单例模式深入解析
【10月更文挑战第31天】在编程世界中,设计模式就像是建筑中的蓝图,它们定义了解决常见问题的最佳实践。本文将通过浅显易懂的语言带你深入了解Java中广泛应用的单例模式,并展示如何实现它。
|
2月前
|
设计模式 SQL 安全
Java编程中的单例模式深入解析
【10月更文挑战第24天】在软件工程中,单例模式是设计模式的一种,它确保一个类只有一个实例,并提供一个全局访问点。本文将探讨如何在Java中使用单例模式,并分析其优缺点以及适用场景。
18 0
|
3月前
|
SQL 设计模式 Java
[Java]单例模式
本文介绍了单例模式的概念及其实现方式,包括饿汉式和懒汉式两种形式,并详细探讨了懒汉式中可能出现的线程安全问题及其解决方案,如锁方法、锁代码块和双重检查锁(DCL)。文章通过示例代码帮助读者更好地理解和应用单例模式。
39 0
|
4月前
|
设计模式 安全 Java
Java 编程中的设计模式:单例模式的深度解析
【9月更文挑战第22天】在Java的世界里,单例模式就像是一位老练的舞者,轻盈地穿梭在对象创建的舞台上。它确保了一个类仅有一个实例,并提供全局访问点。这不仅仅是代码优雅的体现,更是资源管理的高手。我们将一起探索单例模式的奥秘,从基础实现到高级应用,再到它与现代Java版本的舞蹈,让我们揭开单例模式的面纱,一探究竟。
49 11
|
3月前
|
设计模式 SQL 安全
【编程进阶知识】Java单例模式深度解析:饿汉式与懒汉式实现技巧
本文深入解析了Java单例模式中的饿汉式和懒汉式实现方法,包括它们的特点、实现代码和适用场景。通过静态常量、枚举类、静态代码块等方式实现饿汉式,通过非线程安全、同步方法、同步代码块、双重检查锁定和静态内部类等方式实现懒汉式。文章还对比了各种实现方式的优缺点,帮助读者在实际项目中做出更好的设计决策。
72 0
|
5月前
|
设计模式 存储 负载均衡
【五】设计模式~~~创建型模式~~~单例模式(Java)
文章详细介绍了单例模式(Singleton Pattern),这是一种确保一个类只有一个实例,并提供全局访问点的设计模式。文中通过Windows任务管理器的例子阐述了单例模式的动机,解释了如何通过私有构造函数、静态私有成员变量和公有静态方法实现单例模式。接着,通过负载均衡器的案例展示了单例模式的应用,并讨论了单例模式的优点、缺点以及适用场景。最后,文章还探讨了饿汉式和懒汉式单例的实现方式及其比较。
【五】设计模式~~~创建型模式~~~单例模式(Java)
|
5月前
|
设计模式 安全 Java
Java 单例模式,背后有着何种不为人知的秘密?开启探索之旅,寻找答案!
【8月更文挑战第30天】单例模式确保一个类只有一个实例并提供全局访问点,适用于需全局共享的宝贵资源如数据库连接池、日志记录器等。Java中有多种单例模式实现,包括饿汉式、懒汉式、同步方法和双重检查锁定。饿汉式在类加载时创建实例,懒汉式则在首次调用时创建,后者在多线程环境下需使用同步机制保证线程安全。单例模式有助于提高代码的可维护性和扩展性,应根据需求选择合适实现方式。
39 1