Singleton Pattern(单例模式)

单例模式:保证系统中一个类只会产生一个实例,主要解决一个全局使用的类频繁地创建与销毁。

好处

  1. 时间好处 - 省略频繁创建某个常用类对象的时间
  2. 空间好处 - 减少内存使用频率,减轻GC压力

单例模式角色

角色 作用
单例类 提供单例的工厂,返回单例
使用者 获取并使用单例类对象

注意

1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。

饿汉式

优点:没有加锁,执行效率更高!
缺点:类加载时就初始化,浪费内存!

基于classloader机制避免多线程的同步问题,instance在类装载时候进行实例化,无法达到lazy loading效果!

public class Singleton {
private Singleton (){} // private确保单例不会在系统中的其他代码内被实例化
private static Singleton instance = new Singleton();
// static修饰的方法在类加载的时候调用对单例对象实例化(即只要加载该类,单例对象自动实例化浪费空间
public static Singleton getInstance() {
return instance;
}
}

懒汉式

优点:只需要在第一次调用getInstance()方法的时候才会创建单例对象
缺点:为了确保线程安全问题需要添加volatile和synchronized关键字来保证线程安全但每次访问都需要同步会影响性能消耗更多资源

public class LazySingleton
{
private static volatile LazySingleton instance=null; //保证 instance 在所有线程中同步
private LazySingleton(){} //private 避免类在外部被实例化
public static synchronized LazySingleton getInstance()
{
//getInstance 方法前加同步
if(instance==null)
{
instance=new LazySingleton();
}
return instance;
}
}
/* 为了使用延迟加载引入同步关键字反而降低了系统性能*/

懒汉式重构

单例模式使用内部类来维护单例的实例,当Singleton被加载时候不会对内部类进行实例化。只有调用getInstance方法时,才会加载内部类从而初始化单例对象

使用内部类的方式实现单例既可以做到延迟加载也不必使用同步关键字是一种完善的实现

public class Singleton {
private Singleton(){}
// 内部类SingletonHolder实现单例对象初始化
private static class SingletonHolder{
private static Singleton singleton = new Singleton();
}
public static Singleton getInstance(){
// 调用内部类直接获得单例对象
return SingletonHolder.singleton;
}
}

实例

  • DBConnector模拟单例类
public class DBConnector {
private DBConnector(){} // 私有构造方法,禁止在其他类创建单例对象
private static class DBConnectorHolder{
private static final DBConnector dbConnector = new DBConnector();
}
public static DBConnector getInstance(){
return DBConnectorHolder.dbConnector;
}
}
  • 测试
public class TestDemo {
public static void main(String[] args) {
DBConnector dbConnector01 = DBConnector.getInstance();
DBConnector dbConnector02 = DBConnector.getInstance();
System.out.println("dbConnector01内存地址: " + dbConnector01.toString());
System.out.println("dbConnector02内存地址: " + dbConnector02.toString());
System.out.println("dbConnector01的hashcode: " + dbConnector01.hashCode());
System.out.println("dbConnector02的hashcode: " + dbConnector02.hashCode());
System.out.println(dbConnector01 == dbConnector02);
}
}
// 输出
dbConnector01内存地址: ink.openmind.base01.DBConnector@1c53fd30
dbConnector02内存地址: ink.openmind.base01.DBConnector@1c53fd30
dbConnector01的hashcode: 475266352
dbConnector02的hashcode: 475266352
true
posted @   Felix_Openmind  阅读(110)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
*{cursor: url(https://files-cdn.cnblogs.com/files/morango/fish-cursor.ico),auto;}
点击右上角即可分享
微信分享提示