单例学习


/**
* 单例模式,通常单例模式在Java语言中,有两种构建方式:
* 懒汉方式:指全局的单例实例在第一次被使用时构建。
* 饿汉方式:指全局的单例实例在类装载时构建。
* @author xw
*/

public class Single {
//懒汉模式
private static Single instance = null;
/**
* 私有的默认构造子,保证外界无法直接实例化
*/
private Single(){
System.out.println("Single()");
}

/**
* 静态工厂方法,返还此类的惟一实例
*/
synchronized public static Single getInstance()
{
if (instance == null)
{
instance = new Single();
}
System.out.println("getInstance()");
return instance;
}


//饿汉模式
private static final Single instance = new Single();
/**
* 私有的默认构造子,保证外界无法直接实例化
*/
private Single(){
System.out.println("Single()");
}

public static Single getInstance(){
System.out.println("getInstance");
return instance;
}


public static void main(String[] args) {
System.out.println("========================================");
System.out.println("下面是使用单例模式,来调用类的实例");
System.out.println("========================================");
for(int i=0;i<6;i++){
int m=i+1;
System.out.println("第 "+m+" 次"+"得到的对象值为 "+Single.instance);
System.out.println("第 "+m+" 次"+"得到的对象值为 "+Single.getInstance());
}
}
}

1、懒汉方式:
========================================
下面是使用单例模式,来调用类的实例
========================================
第 1 次得到的对象值为 null
Single()
getInstance()
第 1 次得到的对象值为 Single@1f6a7b9
第 2 次得到的对象值为 Single@1f6a7b9
getInstance()
第 2 次得到的对象值为 Single@1f6a7b9
第 3 次得到的对象值为 Single@1f6a7b9
getInstance()
第 3 次得到的对象值为 Single@1f6a7b9
第 4 次得到的对象值为 Single@1f6a7b9
getInstance()
第 4 次得到的对象值为 Single@1f6a7b9
第 5 次得到的对象值为 Single@1f6a7b9
getInstance()
第 5 次得到的对象值为 Single@1f6a7b9
第 6 次得到的对象值为 Single@1f6a7b9
getInstance()
第 6 次得到的对象值为 Single@1f6a7b9

2、饿汉方式
Single()
========================================
下面是使用单例模式,来调用类的实例
========================================
第 1 次得到的对象值为 Single@1f6a7b9
getInstance
第 1 次得到的对象值为 Single@1f6a7b9
第 2 次得到的对象值为 Single@1f6a7b9
getInstance
第 2 次得到的对象值为 Single@1f6a7b9
第 3 次得到的对象值为 Single@1f6a7b9
getInstance
第 3 次得到的对象值为 Single@1f6a7b9
第 4 次得到的对象值为 Single@1f6a7b9
getInstance
第 4 次得到的对象值为 Single@1f6a7b9
第 5 次得到的对象值为 Single@1f6a7b9
getInstance
第 5 次得到的对象值为 Single@1f6a7b9
第 6 次得到的对象值为 Single@1f6a7b9
getInstance
第 6 次得到的对象值为 Single@1f6a7b9
<think> 模式是一种设计模式,确保一个类只有一个实,并提供一个全局访问点。在C++中,实现模式需要注意线程安全、资源释放等问题。 常见的实现方式有: 1. 懒汉式:在第一次需要实时才创建。需要考虑线程安全。 2. 饿汉式:在程序启动时(main函数之前)就创建,线程安全。 3. Meyers' Singleton:利用局部静态变量的特性,在C++11之后是线程安全的。 下面给出几种实现: 1. 懒汉式(线程安全,使用双检锁): ```cpp #include <mutex> class Singleton { public: static Singleton* getInstance() { if (instance_ == nullptr) { // 第一次检查,避免每次加锁 std::lock_guard<std::mutex> lock(mutex_); if (instance_ == nullptr) { // 第二次检查,确保只有一个实被创建 instance_ = new Singleton(); } } return instance_; } // 禁止拷贝和赋值 Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; private: Singleton() = default; ~Singleton() = default; static Singleton* instance_; static std::mutex mutex_; }; // 初始化静态成员 Singleton* Singleton::instance_ = nullptr; std::mutex Singleton::mutex_; ``` 注意:双检锁在C++11之后是安全的,因为C++11规定了内存模型,但对某些编译器(如MSVC)在C++11之前可能安全。 2. 饿汉式(线程安全): ```cpp class Singleton { public: static Singleton* getInstance() { return &instance_; } Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; private: Singleton() = default; ~Singleton() = default; static Singleton instance_; }; // 在程序开始前初始化 Singleton Singleton::instance_; ``` 饿汉式在程序启动时初始化,因此没有线程安全问题。但如果初始化依赖其他静态对象,可能会有顺序问题。 3. Meyers' Singleton(C++11后线程安全): ```cpp class Singleton { public: static Singleton& getInstance() { static Singleton instance; return instance; } Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; private: Singleton() = default; ~Singleton() = default; }; ``` 这是最推荐的实现方式,因为: - C++11保证静态局部变量的初始化是线程安全的。 - 只有第一次调用getInstance()时才会创建实。 - 在程序结束时自动析构,无需手动释放。 注意:以上三种方式中,Meyers' Singleton是最简洁且安全的,推荐使用。 解释: 模式的核心在于防止外部创建对象,因此将构造函数设为私有。同时禁止拷贝和赋值。然后通过静态成员函数来获取唯一实。 相关问题: 1. 为什么双检锁模式中需要两次检查? 2. 饿汉式的缺点是什么? 3. 在C++11之前,如何实现线程安全的? 4. 模式在什么情况下会被破坏? </think> ### C++模式详解 模式确保一个类只有一个实,并提供全局访问点。以下是三种主流实现方式: #### 1. 懒汉式(线程安全双检锁): ```cpp #include <mutex> class Singleton { public: static Singleton* getInstance() { if (instance == nullptr) { // 第一次检查避免每次加锁 std::lock_guard<std::mutex> lock(mtx); if (instance == nullptr) { // 第二次检查确保 instance = new Singleton(); } } return instance; } // 删除拷贝构造和赋值运算符 Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; private: Singleton() {} // 私有构造函数 ~Singleton() {} // 私有析构函数 static Singleton* instance; static std::mutex mtx; }; // 静态成员初始化 Singleton* Singleton::instance = nullptr; std::mutex Singleton::mtx; ``` #### 2. 饿汉式(静态初始化): ```cpp class Singleton { public: static Singleton* getInstance() { return &instance; } Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; private: Singleton() {} ~Singleton() {} static Singleton instance; // 程序启动时即初始化 }; // 静态成员初始化 Singleton Singleton::instance; ``` #### 3. Meyers' Singleton(C++11推荐): ```cpp class Singleton { public: static Singleton& getInstance() { static Singleton instance; // 线程安全的延迟初始化 return instance; } Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; private: Singleton() {} ~Singleton() {} }; ``` ### 关键特性对比: | 实现方式 | 线程安全 | 延迟初始化 | 内存释放 | |----------------|----------|------------|----------------| | 懒汉式(双检锁) | 是 | 是 | 需手动管理 | | 饿汉式 | 是 | 否 | 程序结束时释放 | | Meyers' | 是 | 是 | 自动释放 | ### 核心原理: 1. **私有构造函数**:防止外部直接创建实 2. **静态实**:保证唯一性 3. **全局访问点**:`getInstance()`方法 4. **防拷贝**:删除拷贝构造和赋值运算符 5. **线程安全**:通过互斥锁或静态初始化保证 ### 注意事项: 1. 双检锁在C++11前可能因指令重排导致安全 2. 饿汉式初始化顺序依赖可能导致问题 3. Meyers'方式依赖C++11的静态变量线程安全保证 4. 避免在析构函数中访问其他(可能导致析构顺序问题) ### 典型应用场景: - 配置文件管理 - 日志系统 - 数据库连接池 - 线程池管理 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值