十、设计模式(5)单例模式(Singleton)

本文深入探讨单例模式的五种实现方式,包括饿汉式、懒汉式、双检锁、占位符式及枚举式,分析每种写法的特点与适用场景,特别强调枚举式单例的优势。

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

源文作者:

作者:朱小厮 
来源:优快云 
原文:https://blog.youkuaiyun.com/u013256816/article/details/50975438 



单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

适用性:当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。

单例模式有5中写法(线程安全):

  1. 饿汉式
  2. 懒汉式
  3. 双检索(DCL)
  4. 占位符式(静态内部类)
  5. 枚举式
    下面分别展示这五种写法(详细内容可以参考博主的《singleton模式四种线程安全的实现》和《如何防止单例模式被JAVA反射攻击》)

一、举例

1.饿汉式

public class EagerSingleton {  
        // jvm保证在任何线程访问uniqueInstance静态变量之前一定先创建了此实例  
        private static EagerSingleton uniqueInstance = new EagerSingleton();  

        // 私有的默认构造子,保证外界无法直接实例化  
        private EagerSingleton() {  
        }  

        // 提供全局访问点获取唯一的实例  
        public static EagerSingleton getInstance() {  
                return uniqueInstance;  
        }  
}

2.懒汉式

public class LazySingleton {  
        private static LazySingleton uniqueInstance;  

        private LazySingleton() {  
        }  

        public static synchronized LazySingleton getInstance() {  
                if (uniqueInstance == null)  
                        uniqueInstance = new LazySingleton();  
                return uniqueInstance;  
        }  
}

3.双检锁

public class DoubleCheckedLockingSingleton {  
        // java中使用双重检查锁定机制,由于Java编译器和JIT的优化的原因系统无法保证我们期望的执行次序。  
        // 在java5.0修改了内存模型,使用volatile声明的变量可以强制屏蔽编译器和JIT的优化工作  
        private volatile static DoubleCheckedLockingSingleton uniqueInstance;  

        private DoubleCheckedLockingSingleton() {  
        }  

        public static DoubleCheckedLockingSingleton getInstance() {  
		        DoubleCheckedLockingSingleton localRef = uniqueInstance;
                if (uniqueInstance == null) {  
                        synchronized (DoubleCheckedLockingSingleton.class) {  
		                        localRef = uniqueInstance;
                                if (localRef == null) {  
                                        uniqueInstance = localRef = new DoubleCheckedLockingSingleton();  
                                }  
                        }  
                }  
                return localRef ;  
        }  
}

注意上面的变量localRef,“似乎”看上去显得有点多余。但是实际上绝大多数时候uniqueInstance已经被初始化,引入ocalRef可以使得volatile的只被访问一次(利用return localRef代替return helper),这样可以使得这个单例的整体性能提升25%。

4.占位符式(静态内部类)

public class LazyInitHolderSingleton {  
        private LazyInitHolderSingleton() {  
        }  

        private static class SingletonHolder {  
                private static final LazyInitHolderSingleton INSTANCE = new LazyInitHolderSingleton();  
        }  

        public static LazyInitHolderSingleton getInstance() {  
                return SingletonHolder.INSTANCE;  
        }  
}

 5.枚举式

public enum SingletonClass
{
    INSTANCE;
}

有关枚举的详细资料可以参考《Java枚举类型enum

二、总结

枚举式式最简单最优秀的单例写法,可以防止反射工具(详细参考《如何防止单例模式被JAVA反射攻击》)和序列化破坏(详细参考《JAVA序列化 》),《Effective Java》的作者Joshua Bloch推荐使用这种写法,博主也认为这种写法不错,只是用的人较少,没有普遍性,建议编程时采用占位符式(不能防止反射和序列化破坏),当然写成枚举式就更好啦。

三、Jdk中的单例模式

java.lang.Runtime#getRuntime()

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值