Java创建单例

Java创建单例

1. 饿汉式

类加载时就创建实例

java 复制代码
public class Singleton {
    // 类加载时就创建实例
    private static final Singleton instance = new Singleton();
    
    // 私有构造函数
    private Singleton() {}
    
    // 提供公共的访问方法
    public static Singleton getInstance() {
        return instance;
    }
}

优点: 实现简单,线程安全

缺点: 类加载时就创建,可能造成资源浪费

2. 懒汉式

java 复制代码
public class Singleton {
    private static Singleton instance;
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

优点: 延迟加载

缺点: 线程不安全

3. 懒汉式(线程安全,加锁)

java 复制代码
public class Singleton {
    private static Singleton instance;
    
    private Singleton() {}
    
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

优点: 线程安全,延迟加载

缺点: 每次获取实例都需要同步,性能较差

4. 双重检查锁(DCL,线程安全)

java 复制代码
public class Singleton {
    // volatile关键字防止指令重排序
    private static volatile Singleton instance;
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        if (instance == null) {  // 第一次检查
            synchronized (Singleton.class) {
                if (instance == null) {  // 第二次检查
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

优点: 线程安全,延迟加载,性能较好

缺点: 实现较复杂

5. 静态内部类

java 复制代码
public class Singleton{
	
	//私有构造方法,防止外部实例化
	private Singleton(){
		//防止反射破坏单例
		if(SingletonHolder.instance != null){
			throw new RuntimeException("error, forbiden use reflect!")
		}
	}
	
	//静态内部类 - 持有单例实例
	private static class SingletonHolder {
		// final保证不可变性,JVM保证线程安全
		private static final Singleton instance = new Singleton();
	}
	
	//全局访问点
	public static Singleton getInstance(){
		return SingletonHolder.instance;
	}
}

优点: 线程安全,延迟加载,实现简单

静态内部类单例是《Effective Java》推荐的方式,在不需要防止高级反射攻击和序列化破坏的场景下,是最佳实践之一。

5.1. Volatile的主要功能

  1. 保证可见性
    • 对volatile修饰的变量写操作会立即刷新至主内存,读操作总是从主内存读取新值
    • 保证各个线程对volatile变量的可见性
  2. 禁止指令重排
    • 通过内存屏障防止CPU和编译器对指令进行重排
    • 确保代码执行顺序符合程序预期(对DCL中的instance变量很关键,不加volatile修饰会被指令重排导致获取到一个未初始化的对象(原因:创建对象过程:1.分配内存 2.初始化对象 3.将内存地址指向对象,2和3可能会重排,如果重排,3执行完另一个线程判断instance不为空就会拿到一个没有初始化完成的对象,导致异常))
  3. 不保证原子性
    • 对volatile变量的符合操作(如count++)不是原子的
    • 不能替代synchronized或AtomicXXX类用于线程安全的技术或更新

6. 枚举单例

对象锁和类模板锁

相关推荐
凤凰院凶涛QAQ13 小时前
《Java版数据结构 & 集合类剖析》Map & Set & 反射:“从哈希碰撞到红黑树转换,反射帮你扒开 HashMap 的桶数组看个究竟”
java·数据结构·算法
H.莓飛13 小时前
【数据结构】排序_OJ题(一):计数、桶与排序后的处理
java·开发语言·数据结构
wangchunyu11413 小时前
JAVA AQS与Lock实现原理(含CAS)
java·开发语言·word
爱喝水的鱼丶14 小时前
SAP-ABAP:ECC→S/4HANA ABAP 迁移升级指南——程序改造、语法兼容与性能优化 导语
运维·开发语言·性能优化·sap·abap·经验交流·开发交流
w_zero_one14 小时前
算法--模拟
java·数据结构·算法
小灰灰搞电子15 小时前
Rust+Slint 实现FTP客户端调试助手源码分享
开发语言·后端·rust
外收内放15 小时前
面向对象高级(实战案例)
开发语言·python·学习
Javatutouhouduan15 小时前
阿里1658页Java面试题总结(含答案)
java·高并发·java面试·java面试题·后端开发·java程序员·java八股文
秋天的怀念_David15 小时前
算法一千零一夜 · 第十三夜 幻方,武侠世界里的数学迷宫
java·程序人生·算法
专业程序开发源15 小时前
springboot欧缇蔓月子中心管理系统82697-计算机课程设计、毕业设计
java·spring boot·后端·python·spring·django·课程设计