JAVA设计模式之单例模式

本文详细介绍了Java设计模式中的单例模式,包括其实现方式、优缺点及其应用场景。重点讲解了懒汉式、饿汉式、双检锁及静态内部类等四种实现方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JAVA设计模式之单例模式

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式 。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

要点
  • 单例类只能有一个实例
  • 单例类必须自己创建自己的唯一实例
  • 单例类必须给所有其他对象提供这一实例

主要解决: 一个全局使用的类被频繁的创建和销毁。
何时使用: 当你想控制实例数目,节省系统资源的时候。
如何解决: 判断系统是否已经有这个单例,如果有则返回,如果没有则创建
关键代码: 构造行数是私有的。
优点:
1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如一般网页的头部菜单和尾部导航)。
2、避免对资源的多重占用(比如写文件操作)。


实现方式

1.懒汉式,线程不安全

  • 是否Lazy 初始化: 是,=>在使用的时候才进行初始化,为Lazy 初始化

  • 是否多线程安全: 否,=>因为没有加锁,synchronized

  • 实现难度:

  • 代码demo

     public class LazyModeUnsafeSingleton {
    
     	/** 在类加载的时候创建一次实例 */
     	private static LazyModeUnsafeSingleton instance;
     
     	/** 让构造函数为 private,这样该类就不会被实例化 */
     	private LazyModeUnsafeSingleton() {
     	}
     
     	/** 获取唯一可用的对象 */
     	public static LazyModeUnsafeSingleton newInstance() {
     		if (instance == null) {  
     	        instance = new LazyModeUnsafeSingleton();  
     	    }  
     		return instance;
     	}
     
     	public void showMessage() {
     		System.out.println("Hello World!");
     	}
     }
    

2.懒汉式,线程安全

  • 是否Lazy 初始化: 是,=>在使用的时候才进行初始化,为Lazy 初始化

  • 是否多线程安全: 是,=>加锁,保证同时只有一个线程调用该方法

  • 实现难度:

  • 优点: 第一次调用才初始化,避免内存浪费

  • 缺点: 必须加锁 synchronized 才能保证单例,但加锁会影响效率

  • 代码 demo

     public class LazyModeSingleton {
    
     	/** 在类加载的时候创建一次实例 */
     	private static LazyModeSingleton instance;
     
     	/** 让构造函数为 private,这样该类就不会被实例化 */
     	private LazyModeSingleton() {
     	}
     
     	/** 加锁,保证同时只有一个线程调用该方法,获取唯一可用的对象 */
     	public static synchronized LazyModeSingleton newInstance() {
     		if (instance == null) {  
     	        instance = new LazyModeSingleton();  
     	    }  
     		return instance;
     	}
     
     	public void showMessage() {
     		System.out.println("Hello World!");
     	}
     }
    

3.饿汉式,线程安全

  • 是否Lazy 初始化: 否,=>类在装载的时候进行初始化,非Lazy初始化

  • 是否多线程安全: 是,=>基于 classloder 机制避免了多线程的同步问题

  • 实现难度:

  • 优点: 没有加锁,执行效率会提高。

  • 缺点: 类加载时就初始化,浪费内存

  • 代码demo
    public class HungryModeSingleton {

     	/** 在类加载的时候创建一次实例 */
     	private static HungryModeSingleton instance = new HungryModeSingleton();
     
     	/** 让构造函数为 private,这样该类就不会被实例化 */
     	private HungryModeSingleton() {
     	}
     
     	/** 获取唯一可用的对象 */
     	public static HungryModeSingleton newInstance() {
     		return instance;
     	}
     
     	public void showMessage() {
     		System.out.println("Hello World!");
     	}
     }
    

4.双检锁/双重校验锁(DCL,即 double-checked locking)

  • 是否Lazy 初始化: 是,=>类在装载的时候进行初始化,非Lazy初始化

  • 是否多线程安全: 是,=>因为有加锁,synchronized

  • 实现难度: 较复杂

  • 描述: 这种方式采用双锁机制,安全且在多线程情况下能保持高性能。getInstance() 的性能对应用程序很关键

  • 代码demo

     public class DoubleCheckedLockModeSingleton {
    
     	/** 在类加载的时候创建一次实例 volatile:变量修饰符,直接读写主存 */
     	private volatile static DoubleCheckedLockModeSingleton instance = null;
     
     	/** 让构造函数为 private,这样该类就不会被实例化 */
     	private DoubleCheckedLockModeSingleton() {
     	}
     
     	/** 获取唯一可用的对象 */
     	public static DoubleCheckedLockModeSingleton newInstance() {
     		// 为空表示第一次调用该方法
     		if (instance == null) {
     			// 保证并发null进入该方法块的时候,设置锁
     			synchronized (DoubleCheckedLockModeSingleton.class) {
     				if (instance == null) {
     					instance = new DoubleCheckedLockModeSingleton();
     				}
     			}
     		}
     		return instance;
     	}
     
     	public void showMessage() {
     		System.out.println("Hello World!");
     	}
    

    }

5.登记式/静态内部类

  • 是否Lazy 初始化: 是,=>类在装载的时候进行初始化,非Lazy初始化

  • 是否多线程安全: 是,=>因为没有加锁,synchronized

  • 实现难度: 一般

  • 描述: 种方式能达到双检锁方式一样的功效,但实现更简单。对静态域使用延迟初始化,应使用这种方式而不是双检锁方式。这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用。
    这种方式同样利用了 classloder 机制来保证初始化 instance 时只有一个线程,它跟第 3 种方式不同的是:第 3 种方式只要 Singleton 类被装载了,那么 instance 就会被实例化(没有达到 lazy loading 效果),而这种方式是 Singleton 类被装载了,instance 不一定被初始化。因为 SingletonHolder 类没有被主动使用,只有通过显式调用 getInstance 方法时,才会显式装载 SingletonHolder 类,从而实例化 instance。想象一下,如果实例化 instance 很消耗资源,所以想让它延迟加载,另外一方面,又不希望在 Singleton 类加载时就实例化,因为不能确保 Singleton 类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化 instance 显然是不合适的。这个时候,这种方式相比第 3 种方式就显得很合理。

  • 代码demo

     public class StaticModeSingleton {
    
     	private static class StaticModeSingletonHolder{
     		 private static final StaticModeSingleton INSTANCE = new StaticModeSingleton();  
     	}
     
     	/** 让构造函数为 private,这样该类就不会被实例化 */
     	private StaticModeSingleton() {
     	}
     
     	/** 获取唯一可用的对象 */
     	public static StaticModeSingleton newInstance() {
     		return StaticModeSingletonHolder.INSTANCE;
     	}
     
     	public void showMessage() {
     		System.out.println("Hello World!");
     	}
    

    }

测试代码

public static void main(String[] args) {

	// 获取唯一可用的对象
	StaticModeSingleton staticModeSingleton = StaticModeSingleton.newInstance();

	// 执行动作
	staticModeSingleton.showMessage();
}

一般情况下,不建议使用第 1 种和第 2 种懒汉方式,建议使用第 3 种饿汉方式。只有在要明确实现 lazy loading 效果时,才会使用第 5 种登记方式。如果有其他特殊的需求,可以考虑使用第 4 种双检锁方式

资源下载链接为: https://pan.quark.cn/s/22ca96b7bd39 在 IT 领域,文档格式转换是常见需求,尤其在处理多种文件类型时。本文将聚焦于利用 Java 技术栈,尤其是 Apache POI 和 iTextPDF 库,实现 doc、xls(涵盖 Excel 2003 及 Excel 2007+)以及 txt、图片等格式文件向 PDF 的转换,并实现在线浏览功能。 先从 Apache POI 说起,它是一个强大的 Java 库,专注于处理 Microsoft Office 格式文件,比如 doc 和 xls。Apache POI 提供了 HSSF 和 XSSF 两个 API,其中 HSSF 用于读写老版本的 BIFF8 格式(Excel 97-2003),XSSF 则针对新的 XML 格式(Excel 2007+)。这两个 API 均具备读取和写入工作表、单元格、公式、样式等功能。读取 Excel 文件时,可通过创建 HSSFWorkbook 或 XSSFWorkbook 对象来打开相应格式的文件,进而遍历工作簿中的每个 Sheet,获取行和列数据。写入 Excel 文件时,创建新的 Workbook 对象,添加 Sheet、Row 和 Cell,即可构建新 Excel 文件。 再看 iTextPDF,它是一个用于生成和修改 PDF 文档的 Java 库,拥有丰富的 API。创建 PDF 文档时,借助 Document 对象,可定义页面尺寸、边距等属性来定制 PDF 外观。添加内容方面,可使用 Paragraph、List、Table 等元素将文本、列表和表格加入 PDF,图片可通过 Image 类加载插入。iTextPDF 支持多种字体和样式,可设置文本颜色、大小、样式等。此外,iTextPDF 的 TextRenderer 类能将 HTML、
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值