【编程进阶知识】Java单例模式深度解析:饿汉式与懒汉式实现技巧

简介: 本文深入解析了Java单例模式中的饿汉式和懒汉式实现方法,包括它们的特点、实现代码和适用场景。通过静态常量、枚举类、静态代码块等方式实现饿汉式,通过非线程安全、同步方法、同步代码块、双重检查锁定和静态内部类等方式实现懒汉式。文章还对比了各种实现方式的优缺点,帮助读者在实际项目中做出更好的设计决策。

Java单例模式深度解析:饿汉式与懒汉式实现技巧

摘要: 在Java编程中,单例模式是一种常用的设计模式,用于确保一个类只有一个实例,并提供一个全局访问点。本文深入探讨了饿汉式和懒汉式单例模式的实现方法,包括它们的特点、实现代码和适用场景。通过阅读本文,你将能够理解单例模式的核心要点,并掌握如何在实际项目中正确应用这两种单例模式。

关键词: Java单例模式,饿汉式,懒汉式,设计模式,线程安全

1. 单例模式概述

单例模式是一种创建型设计模式,它确保某个类只有一个实例,并提供一个全局访问点。这种模式在Java中广泛应用,如Runtime类。

核心要点:

  1. 唯一实例: 类的实例必须是唯一的。
  2. 内部创建: 构造器必须私有化,防止外部创建实例。
  3. 全局访问: 提供一个公共的静态方法获取实例。
  4. 创建时机: 分为饿汉式和懒汉式。

2. 饿汉式单例模式

饿汉式单例模式在类加载时就创建实例,避免了线程同步问题。

2.1 实现方式

  1. 静态常量实例化
  2. 枚举类
  3. 静态代码块

2.2 代码示例

//1、静态常量直接实例化(代表jvm运行环境的Runtime类生成单例,采用的就是这种实现方式,简洁直观);
class HungrySigleton1 {
   
    private HungrySigleton1(){
   
    }
    private final static HungrySigleton1 INSTANCE = new HungrySigleton1();
    public static HungrySigleton1 getInstance(){
   
        return INSTANCE;
    }
}

//2、枚举类(最简洁);
enum HungrySigleton3{
   
    INSTANCE;
    private HungrySigleton3() {
   
    }
}

//3、静态代码块(适合复杂的场景,如从配置文件读取所需参数)。
class HungrySigleton2 {
   
    private HungrySigleton2(String info){
   System.out.println(info);}
    private  static HungrySigleton2 INSTANCE =null;
    static {
   
        Properties prop = new Properties();
        InputStream inStream = HungrySigleton2.class.getClassLoader().getResourceAsStream("project.properties");
        try {
   prop.load(inStream);} catch (IOException e) {
   e.printStackTrace();}
        String info =(String) prop.get("info");
        //扩展:读取配置文件的几种方式 1、Properties继承自Hashtable 2、ResourceBundle 3、Spring种利用ApplicationContext加载xml文件
         INSTANCE = new HungrySigleton2(info);
    }
    public static HungrySigleton2 getInstance(){
   
        return INSTANCE;
    }
}
public class Hungry{
   
    public static void main(String[] args) {
   
        HungrySigleton1 ins1 = HungrySigleton1.getInstance();
        HungrySigleton2 ins2 = HungrySigleton2.getInstance();
        HungrySigleton3 ins3 = HungrySigleton3.INSTANCE;
    }
}

3. 懒汉式单例模式

懒汉式单例模式在第一次使用时才创建实例,可能需要处理线程同步问题。

3.1 实现方式

  1. 非线程安全版本
  2. 同步方法实现
  3. 同步代码块实现
  4. 双重检查锁定(DCL)
  5. 静态内部类

3.2 代码示例

class LazySigleton1 {
   
    private LazySigleton1(){
   
    }
    private  static LazySigleton1 INSTANCE =null;
    public static LazySigleton1 getInstance(){
   
        if(null == INSTANCE){
   
            INSTANCE = new LazySigleton1();
        }
        return INSTANCE;
    }
}

//2、懒汉式版本2(同步方法实现线程安全,但效率很低);
class LazySigleton2 {
   
    private LazySigleton2(){
   
    }
    private  static LazySigleton2 INSTANCE =null;
    public synchronized static LazySigleton2 getInstance(){
   
        if(null == INSTANCE){
   
            try {
   Thread.sleep(100);} catch (InterruptedException e) {
   e.printStackTrace();}
            INSTANCE = new LazySigleton2();
        }
        return INSTANCE;
    }
}

//3、懒汉式版本2(同步代码块提供了一定效率,但存在线程安全问题);
class LazySigleton3 {
   
    private LazySigleton3(){
   
    }
    private  static LazySigleton3 INSTANCE =null;
    public  static LazySigleton3 getInstance(){
   
        if(null == INSTANCE){
   
            try {
   Thread.sleep(100);} catch (InterruptedException e) {
   e.printStackTrace();}
            synchronized(INSTANCE){
   
                INSTANCE = new LazySigleton3();
            }
        }
        return INSTANCE;
    }
}

//4、懒汉式版本2(DCL(Double Check Lock),线程安全效率较高,但由于synchronized无法避免jvm优化时可能出现的乱序执行,可能会遇到拿到的实例对象尚未被正确初始化的问题,这时可以利用volatile来解决);
class LazySigleton4 {
   
    private LazySigleton4(){
   
    }
    private  static volatile LazySigleton4 INSTANCE =null;
    public  static LazySigleton4 getInstance(){
   
        if(null == INSTANCE){
   
            try {
   Thread.sleep(100);} catch (InterruptedException e) {
   e.printStackTrace();}
            synchronized(INSTANCE){
   
                if(null == INSTANCE){
   
                    INSTANCE = new LazySigleton4();
                }
            }
        }
        return INSTANCE;
    }
}
//5、静态内部类(内部类被加载和初始化时才会创建对象,即调用时)
class LazySigleton5 {
   
    private LazySigleton5(){
   
    }
    private static class Inner{
   
         private final static LazySigleton5 INSTANCE = new LazySigleton5();
    }
    public static LazySigleton5 getInstance(){
   
        return Inner.INSTANCE;
    }
}

public class Lazy {
   
    public static void main(String[] args) throws InterruptedException, ExecutionException {
   
        ExecutorService exec = Executors.newFixedThreadPool(2);
        Callable task = new Callable(){
   
            @Override
            public Object call() {
   
                LazySigleton1 instance = LazySigleton1.getInstance();
                System.out.println(Thread.currentThread().getName()+instance);
                return instance;
            }
        };
        Future f1 = exec.submit(task);
        Future f2 = exec.submit(task);
        LazySigleton1 l1 = (LazySigleton1) f1.get(),l2 = (LazySigleton1) f2.get();
        System.out.println("l1:" + l1);
        System.out.println("l2:" + l2);
        System.out.println(l1==l2);
        exec.shutdown();
    }
}

4. 优缺点对比

实现方式 优点 缺点
饿汉式 - 线程安全
- 简单直观
- 类加载时就创建实例,可能导致资源浪费
懒汉式非线程安全 - 延迟实例化
- 节省资源
- 非线程安全
懒汉式同步方法 - 线程安全 - 效率低,每次访问都要同步
懒汉式同步代码块 - 线程安全
- 效率较高
- 复杂的线程同步问题
双重检查锁定 - 线程安全
- 高效
- 需要处理指令重排问题
静态内部类 - 线程安全
- 延迟加载
- 代码复杂度较高

5. 流程图

graph TD
    A[开始] --> B[检查实例]
    B -->|不存在| C[创建实例]
    B -->|存在| D[返回实例]
    C --> D

6. 结语

单例模式是Java中一种非常重要的设计模式,适用于需要严格控制实例数量的场景。通过本文的介绍,你应该对饿汉式和懒汉式单例模式有了更深入的理解。希望这些信息能帮助你在实际开发中做出更好的设计决策。

思维导图:

graph LR
    A[单例模式] --> B[饿汉式]
    A --> C[懒汉式]
    B --> D[静态常量]
    B --> E[枚举类]
    B --> F[静态代码块]
    C --> G[非线程安全]
    C --> H[同步方法]
    C --> I[同步代码块]
    C --> J[双重检查锁定]
    C --> K[静态内部类]

Excel表格:

实现方式 优点 缺点
饿汉式 - 线程安全
- 简单直观
- 类加载时就创建实例,可能导致资源浪费
懒汉式非线程安全 - 延迟实例化
- 节省资源
- 非线程安全
懒汉式同步方法 - 线程安全 - 效率低,每次访问都要同步
懒汉式同步代码块 - 线程安全
- 效率较高
- 复杂的线程同步问题
双重检查锁定 - 线程安全
- 高效
- 需要处理指令重排问题
静态内部类 - 线程安全
- 延迟加载
- 代码复杂度较高

鼓励话语: 掌握单例模式,就像是掌握了控制Java世界的一把钥匙。如果你有更多的见解或者遇到了难题,不妨在评论区分享,让我们一起探讨,共同进步!

目录
相关文章
|
27天前
|
安全 Java 数据库连接
2025 年最新 Java 学习路线图含实操指南助你高效入门 Java 编程掌握核心技能
2025年最新Java学习路线图,涵盖基础环境搭建、核心特性(如密封类、虚拟线程)、模块化开发、响应式编程、主流框架(Spring Boot 3、Spring Security 6)、数据库操作(JPA + Hibernate 6)及微服务实战,助你掌握企业级开发技能。
203 3
|
1月前
|
缓存 安全 Java
Java并发性能优化|读写锁与互斥锁解析
本文深入解析Java中两种核心锁机制——互斥锁与读写锁,通过概念对比、代码示例及性能测试,揭示其适用场景。互斥锁适用于写多或强一致性场景,读写锁则在读多写少时显著提升并发性能。结合锁降级、公平模式等高级特性,助你编写高效稳定的并发程序。
109 0
|
1月前
|
安全 Oracle Java
JAVA高级开发必备·卓伊凡详细JDK、JRE、JVM与Java生态深度解析-形象比喻系统理解-优雅草卓伊凡
JAVA高级开发必备·卓伊凡详细JDK、JRE、JVM与Java生态深度解析-形象比喻系统理解-优雅草卓伊凡
163 0
JAVA高级开发必备·卓伊凡详细JDK、JRE、JVM与Java生态深度解析-形象比喻系统理解-优雅草卓伊凡
|
30天前
|
算法 Java 测试技术
零基础学 Java: 从语法入门到企业级项目实战的详细学习路线解析
本文为零基础学习者提供完整的Java学习路线,涵盖语法基础、面向对象编程、数据结构与算法、多线程、JVM原理、Spring框架、Spring Boot及项目实战,助你从入门到进阶,系统掌握Java编程技能,提升实战开发能力。
84 0
|
2月前
|
存储 Java Linux
操作系统层面视角下 Java IO 的演进路径及核心技术变革解析
本文从操作系统层面深入解析Java IO的演进历程,涵盖BIO、NIO、多路复用器及Netty等核心技术。分析各阶段IO模型的原理、优缺点及系统调用机制,探讨Java如何通过底层优化提升并发性能与数据处理效率,全面呈现IO技术的变革路径与发展趋势。
54 1
|
1月前
|
Java
Java编程:理解while循环的使用
总结而言, 使用 while 迴圈可以有效解决需要多次重复操作直至特定條件被触发才停止執行任务场景下问题; 它简单、灵活、易于实现各种逻辑控制需求但同时也要注意防止因邏各错误导致無限迁璇発生及及時處理可能発生异常以确保程序稳定运作。
166 0
|
1月前
|
安全 Cloud Native Java
Java:历久弥新的企业级编程基石
Java:历久弥新的企业级编程基石
|
1月前
|
移动开发 Cloud Native Java
Java:历久弥新的企业级编程基石
Java:历久弥新的企业级编程基石
|
2月前
|
安全 Java API
Java 集合高级应用与实战技巧之高效运用方法及实战案例解析
本课程深入讲解Java集合的高级应用与实战技巧,涵盖Stream API、并行处理、Optional类、现代化Map操作、不可变集合、异步处理及高级排序等核心内容,结合丰富示例,助你掌握Java集合的高效运用,提升代码质量与开发效率。
193 0
|
2月前
|
设计模式 Java 数据库连接
Java编程的知识体系 | Java编程精要
Java是一种广泛使用的通用编程语言,具备面向对象、跨平台、安全简单等优势,适用于桌面、企业、Web、移动及大数据等多个领域。它功能强大且易于学习,是程序设计入门和面向对象思想学习的优选语言。本书系统讲解Java编程知识,涵盖技术核心与应用拓展两大模块,内容包括基础语法、面向对象设计、GUI、数据库、多线程、网络编程及Web开发等,帮助读者全面掌握Java开发技能。
77 0

热门文章

最新文章

推荐镜像

更多
  • DNS