设计模式:单例模式(Singleton)


欢迎支持笔者新作:《深入理解Kafka:核心设计与实践原理》和《RabbitMQ实战指南》,同时欢迎关注笔者的微信公众号:朱小厮的博客。


欢迎跳转到本文的原文链接:https://honeypps.com/design_pattern/singleton/

  单例模式在23个设计模式中算得上是最简单的一个了,也许你会有异议,那就换成“最简单之一”,这样就严谨了很多。
  单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
  适用性:当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。
这里写图片描述

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

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

饿汉式

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

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

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

懒汉式

public class LazySingleton {  
        private static LazySingleton uniqueInstance;  

        private LazySingleton() {  
        }  

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

双检锁

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%。更多可以参考wiki百科


占位符式

public class LazyInitHolderSingleton {  
        private LazyInitHolderSingleton() {  
        }  

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

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

枚举式

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

public enum SingletonClass
{
    INSTANCE;
}

Jdk中的单例模式:
java.lang.Runtime#getRuntime()


总结

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

参考资料

  1. singleton模式四种线程安全的实现
  2. 如何防止单例模式被JAVA反射攻击
  3. JAVA序列化
  4. Java枚举类型enum
  5. 《Effective Java(Second Edition)》Joshua Bloch.
  6. 细数JDK里的设计模式

欢迎跳转到本文的原文链接:https://honeypps.com/design_pattern/singleton/

欢迎支持笔者新作:《深入理解Kafka:核心设计与实践原理》和《RabbitMQ实战指南》,同时欢迎关注笔者的微信公众号:朱小厮的博客。


<think>好的,用户想了解如何用不同编程语言实现单例设计模式。首先,我需要回顾单例模式的基本概念,确保自己理解正确。单例模式确保一个类只有一个实例,并提供全局访问点。根据引用中的资料,不同语言有不同的实现方式,比如Java、C、Go等。 接下来,我需要整理各个语言的实现方法。首先看Java,用户提供的引用[1]提到使用泛型实现单例,引用[4]展示了懒汉式线程不安全的例子。但线程安全需要考虑,比如双重检查锁或者静态内部类。然后C语言,引用[2]提到使用静态指针和全局访问函数,可能需要静态变量和互斥锁来保证线程安全。Go语言在引用[4]中有懒汉式示例,但线程安全需要用sync.Once。 然后,Python的实现通常可以用模块级别的变量,或者通过类装饰器、元类来实现。用户可能还希望了解其他语言比如C#或JavaScript,但引用中没有提到,需要根据现有知识补充。 需要注意各个实现中的线程安全问题和延迟初始化(懒汉vs饿汉)。同时,不同语言的语法特性不同,比如Java的静态变量,C的静态指针,Go的sync.Once,Python的装饰器等。 还要检查每个示例是否符合单例模式的要点:私有构造函数、静态实例获取方法、线程安全、防止反射/反序列化破坏单例等。不过根据用户的问题,可能只需要基本实现,不需要深入细节。 最后,确保回答结构清晰,分语言说明,给出代码示例,并标注引用来源。同时生成相关问题,如线程安全、应用场景、优缺点等,帮助用户进一步学习。</think>### 单例设计模式实现方法(多语言示例) 单例模式通过限制类的实例化次数为1次,并提供全局访问点来确保唯一性[^3]。以下是不同编程语言的实现方法: --- #### 1. **Java实现** - **饿汉式**(线程安全,类加载时初始化): ```java public class Singleton { private static final Singleton instance = new Singleton(); private Singleton() {} // 私有构造函数 public static Singleton getInstance() { return instance; } } ``` - **懒汉式+双重检查锁**(延迟初始化,线程安全)[^4]: ```java public class Singleton { 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; } } ``` --- #### 2. **C语言实现** - **静态指针+全局访问函数**(需手动管理线程安全)[^2]: ```c typedef struct Singleton { int data; } Singleton; static Singleton* instance = NULL; Singleton* getInstance() { if (instance == NULL) { instance = (Singleton*)malloc(sizeof(Singleton)); instance->data = 0; } return instance; } ``` --- #### 3. **Go语言实现** - **sync.Once实现**(线程安全,延迟初始化)[^4]: ```go package main import "sync" type Singleton struct { Data int } var instance *Singleton var once sync.Once func GetInstance() *Singleton { once.Do(func() { instance = &Singleton{Data: 42} }) return instance } ``` --- #### 4. **Python实现** - **模块级变量**(天然单例): ```python class Singleton: _instance = None def __new__(cls): if cls._instance is None: cls._instance = super().__new__(cls) return cls._instance ``` - **装饰器实现**(通用性强): ```python def singleton(cls): instances = {} def get_instance(*args, **kwargs): if cls not in instances: instances[cls] = cls(*args, **kwargs) return instances[cls] return get_instance @singleton class MyClass: pass ``` --- ### 关键实现要点 1. **私有构造函数**:防止外部直接实例化[^3]。 2. **静态实例访问方法**:如`getInstance()`。 3. **线程安全**:通过锁或原子操作(如Java双重检查锁、Go的`sync.Once`)。 4. **延迟初始化**:按需创建实例(懒汉式)[^4]。 ---
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值