设计模式-单例模式-懒汉式饿汉式探讨

news/2025/2/12 8:39:36/

文章目录

      • 基础概念
      • 饿汉式实例
      • 懒汉式实例
      • 懒汉式实例【互斥锁方式保障线程安全】
      • 懒汉式实例【双重检查锁定(Double-Checked Locking)保障线程安全】
      • 大型项目中单例模式实用
        • 数据库连接池
        • C语言-单例模式实现线程池
        • C语言单例模式-实现日志管理器
        • C语言单例模式-实现高性能配置管理器

基础概念

单例模式是一种常用的设计模式,它可以保证一个类只有一个实例对象,并提供一个全局访问点来访问该实例对象。在实际开发中,常常需要使用单例模式来管理全局资源,例如数据库连接池、线程池等。

单例模式可以分为懒汉式和饿汉式两种实现方式。

懒汉式单例模式是指在第一次使用实例对象时才创建实例对象,而不是在程序启动时就创建实例对象。
懒汉式单例模式的优点是可以节省系统资源,缺点是在多线程环境下可能会出现多个线程同时创建实例对象的问题,需要进行线程安全处理。
饿汉式单例模式是指在程序启动时就创建实例对象(并申请分配内存),而不是在第一次使用实例对象时才创建实例对象。
饿汉式单例模式的优点是可以避免多线程环境下的线程安全问题,缺点是可能会浪费系统资源。

饿汉式实例

#include <stdio.h>
#include <stdlib.h>typedef struct {int id;char* name;
} Singleton;static Singleton* instance = NULL;/* 只此仅当程序第一次起来,仅跑一次 */
void init_instance() {instance = (Singleton*)malloc(sizeof(Singleton));instance->id = 1;instance->name = "Singleton";
}Singleton* get_instance() {return instance;
}int main() {init_instance();	/* 程序一开始,就必须执行。不然,与懒汉式无较大差异 */Singleton* singleton = get_instance();printf("id: %d, name: %s\n", singleton->id, singleton->name);free(instance);return 0;
}

懒汉式实例

懒汉式实例【互斥锁方式保障线程安全】

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>/* 懒汉单例模式 */
/* 互斥锁方式保障线程安全 */typedef struct {int id;char* name;
} Singleton;static Singleton* instance = NULL;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;Singleton* get_instance() {/* 检查实例对象存在性时,获取互斥锁,存在性能开销问题 */pthread_mutex_lock(&mutex);if (instance == NULL) {instance = (Singleton*)malloc(sizeof(Singleton));instance->id = 1;instance->name = "Singleton";}pthread_mutex_unlock(&mutex);return instance;
}int main() {Singleton* singleton1 = get_instance();Singleton* singleton2 = get_instance();printf("singleton1: %p, singleton2: %p\n", singleton1, singleton2);return 0;
}

懒汉式实例【双重检查锁定(Double-Checked Locking)保障线程安全】

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>/* 懒汉单例模式 */
/* 双重检查锁定(Double-Checked Locking)保障线程安全 */typedef struct {int id;char* name;
} Singleton;static Singleton* instance = NULL;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;Singleton* get_instance() {/* 优势:* 在第一次检查实例对象是否存在时,不需要获取互斥锁,* 这可以避免每次调用get_instance函数时都需要获取互斥锁的性能问题。* 只有在实例对象不存在时,才获取互斥锁,并再次检查实例对象是否存在,以避免多个线程同时创建实例对象的问题。 *//* 隐患:在使用双重检查锁定方式时,需要保证编译器对静态变量的初始化顺序,否则可能会导致线程安全问题。 */if (instance == NULL) {	/* 第一次判空,即第一次检查 */pthread_mutex_lock(&mutex);if (instance == NULL) {	/* 第二次判空,即第二次检查 */instance = (Singleton*)malloc(sizeof(Singleton));instance->id = 1;instance->name = "Singleton";}pthread_mutex_unlock(&mutex);}return instance;
}int main() {Singleton* singleton1 = get_instance();Singleton* singleton2 = get_instance();printf("singleton1: %p, singleton2: %p\n", singleton1, singleton2);return 0;
}

大型项目中单例模式实用

  1. 数据库连接池:在大型项目中,通常需要频繁地访问数据库,为了提高数据库访问效率,可以使用数据库连接池来管理数据库连接。数据库连接池可以使用单例模式来实现,保证只有一个数据库连接池实例对象,并提供一个全局访问点来访问该实例对象。

  2. 线程池:在大型项目中,通常需要使用多线程来提高系统并发能力,为了避免频繁地创建和销毁线程,可以使用线程池来管理线程。线程池可以使用单例模式来实现,保证只有一个线程池实例对象,并提供一个全局访问点来访问该实例对象。

  3. 日志管理器:在大型项目中,通常需要记录系统运行日志,为了方便管理和维护日志,可以使用日志管理器来管理系统日志。日志管理器可以使用单例模式来实现,保证只有一个日志管理器实例对象,并提供一个全局访问点来访问该实例对象。

  4. 配置管理器:在大型项目中,通常需要读取和管理系统配置信息,为了方便管理和维护配置信息,可以使用配置管理器来管理系统配置信息。配置管理器可以使用单例模式来实现,保证只有一个配置管理器实例对象,并提供一个全局访问点来访问该实例对象。

数据库连接池


/* C语言实现的简单的数据库连接池的饿汉式单例模式 */#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>#define MAX_CONNECTIONS 10typedef struct {int id;char* url;char* username;char* password;
} Connection;typedef struct {Connection* connections[MAX_CONNECTIONS];int count;pthread_mutex_t lock;
} ConnectionPool;static ConnectionPool* instance = NULL;Connection* create_connection(int id, const char* url, const char* username, const char* password) {Connection* conn = (Connection*)malloc(sizeof(Connection));conn->id = id;conn->url = strdup(url);conn->username = strdup(username);conn->password = strdup(password);return conn;
}void destroy_connection(Connection* conn) {free(conn->url);free(conn->username);free(conn->password);free(conn);
}void init_instance() {instance = (ConnectionPool*)malloc(sizeof(ConnectionPool));instance->count = 0;pthread_mutex_init(&instance->lock, NULL);
}ConnectionPool* get_instance() {return instance;
}Connection* get_connection() {ConnectionPool* pool = get_instance();pthread_mutex_lock(&pool->lock);Connection* conn = NULL;if (pool->count > 0) {conn = pool->connections[--pool->count];}pthread_mutex_unlock(&pool->lock);return conn;
}void release_connection(Connection* conn) {ConnectionPool* pool = get_instance();pthread_mutex_lock(&pool->lock);if (pool->count < MAX_CONNECTIONS) {pool->connections[pool->count++] = conn;} else {destroy_connection(conn);}pthread_mutex_unlock(&pool->lock);
}int main() {init_instance();	/* 程序一开始,就必须执行。不然,与懒汉式无较大差异 */ConnectionPool* pool = get_instance();for (int i = 0; i < MAX_CONNECTIONS; i++) {Connection* conn = create_connection(i, "localhost", "root", "password");pool->connections[pool->count++] = conn;}Connection* conn1 = get_connection();Connection* conn2 = get_connection();printf("conn1: %p\n", conn1);printf("conn2: %p\n", conn2);release_connection(conn1);release_connection(conn2);return 0;
}

C语言-单例模式实现线程池

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>#define THREAD_POOL_SIZE 5// 任务结构体
typedef struct {void (*task)(void*);void* arg;
} Task;// 线程池结构体
typedef struct {Task* tasks; // 任务队列int size; // 任务队列大小int head; // 任务队列头指针int tail; // 任务队列尾指针int count; // 任务队列中任务数量pthread_mutex_t lock; // 互斥锁pthread_cond_t not_empty; // 非空条件变量pthread_cond_t not_full; // 非满条件变量int shutdown; // 线程池是否关闭pthread_t* threads; // 工作线程数组int thread_count; // 工作线程数量
} ThreadPool;// 线程池单例结构体
typedef struct {ThreadPool* pool; // 线程池指针
} ThreadPoolSingleton;static ThreadPoolSingleton* instance = NULL; // 线程池单例对象指针// 工作线程函数
void* worker(void* arg) {ThreadPool* pool = (ThreadPool*)arg;while (1) {pthread_mutex_lock(&pool->lock);while (pool->count == 0 && !pool->shutdown) {pthread_cond_wait(&pool->not_empty, &pool->lock);}if (pool->count == 0 && pool->shutdown) {pthread_mutex_unlock(&pool->lock);pthread_exit(NULL);}Task task = pool->tasks[pool->head];pool->head = (pool->head + 1) % pool->size;pool->count--;pthread_cond_signal(&pool->not_full);pthread_mutex_unlock(&pool->lock);task.task(task.arg);}return NULL;
}// 创建线程池函数
ThreadPool* create_thread_pool(int thread_count, int queue_size) {ThreadPool* pool = (ThreadPool*)malloc(sizeof(ThreadPool));pool->tasks = (Task*)malloc(sizeof(Task) * queue_size);pool->size = queue_size;pool->head = 0;pool->tail = 0;pool->count = 0;pthread_mutex_init(&pool->lock, NULL);pthread_cond_init(&pool->not_empty, NULL);pthread_cond_init(&pool->not_full, NULL);pool->shutdown = 0;pool->threads = (pthread_t*)malloc(sizeof(pthread_t) * thread_count);pool->thread_count = thread_count;for (int i = 0; i < thread_count; i++) {pthread_create(&pool->threads[i], NULL, worker, pool);}return pool;
}// 销毁线程池函数
void destroy_thread_pool(ThreadPool* pool) {pthread_mutex_lock(&pool->lock);pool->shutdown = 1;pthread_mutex_unlock(&pool->lock);pthread_cond_broadcast(&pool->not_empty);for (int i = 0; i < pool->thread_count; i++) {pthread_join(pool->threads[i], NULL);}free(pool->threads);free(pool->tasks);pthread_mutex_destroy(&pool->lock);pthread_cond_destroy(&pool->not_empty);pthread_cond_destroy(&pool->not_full);free(pool);
}// 提交任务函数
void submit_task(ThreadPool* pool, void (*task)(void*), void* arg) {pthread_mutex_lock(&pool->lock);while (pool->count == pool->size && !pool->shutdown) {pthread_cond_wait(&pool->not_full, &pool->lock);}if (pool->shutdown) {pthread_mutex_unlock(&pool->lock);return;}pool->tasks[pool->tail].task = task;pool->tasks[pool->tail].arg = arg;pool->tail = (pool->tail + 1) % pool->size;pool->count++;pthread_cond_signal(&pool->not_empty);pthread_mutex_unlock(&pool->lock);
}// 任务函数
void task_func(void* arg) {int* num = (int*)arg;printf("task %d is running\n", *num);free(num);
}// 任务包装函数
void* task_wrapper(void* arg) {TaskWrapper* wrapper = (TaskWrapper*)arg;submit_task(wrapper->pool, wrapper->task, wrapper->arg);free(wrapper);return NULL;
}init_instance() {instance = (ThreadPoolSingleton*)malloc(sizeof(ThreadPoolSingleton));instance->pool = create_thread_pool(THREAD_POOL_SIZE, THREAD_POOL_SIZE);
}
// 获取线程池单例对象函数
ThreadPool* get_thread_pool_instance() {return instance->pool;
}int main() {init_instance();	/* 程序一开始,就必须执行。不然,与懒汉式无较大差异 */ThreadPool* pool = get_thread_pool_instance(); // 获取线程池单例对象for (int i = 0; i < 10; i++) {int* num = (int*)malloc(sizeof(int));*num = i;TaskWrapper* wrapper = (TaskWrapper*)malloc(sizeof(TaskWrapper));wrapper->pool = poolwrapper->task = task_func;wrapper->arg = num;pthread_t tid;pthread_create(&tid, NULL, task_wrapper, wrapper); // 提交任务}sleep(1); // 等待所有任务执行完毕destroy_thread_pool(pool); // 销毁线程池return 0;
}/*
该示例代码中,使用了单例模式来创建线程池对象,保证了整个程序中只有一个线程池对象。
线程池中包含了任务队列、工作线程数组、互斥锁、条件变量等成员,通过这些成员来实现任务的提交和执行。
在主函数中,提交了10个任务,每个任务都是一个简单的打印数字的函数,最后等待所有任务执行完毕后销毁线程池。
*/

C语言单例模式-实现日志管理器

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <pthread.h>// 日志级别枚举
typedef enum {LOG_LEVEL_DEBUG,LOG_LEVEL_INFO,LOG_LEVEL_WARN,LOG_LEVEL_ERROR,LOG_LEVEL_FATAL
} LogLevel;// 日志管理器结构体
typedef struct {FILE* file; // 日志文件指针LogLevel level; // 日志级别pthread_mutex_t lock; // 互斥锁
} LogManager;// 日志管理器单例结构体
typedef struct {LogManager* manager; // 日志管理器指针
} LogManagerSingleton;static LogManagerSingleton* instance = NULL; // 日志管理器单例对象指针// 获取当前时间字符串函数
void get_current_time_string(char* buffer, size_t size) {time_t now = time(NULL);struct tm* tm = localtime(&now);strftime(buffer, size, "%Y-%m-%d %H:%M:%S", tm);
}// 写日志函数
void write_log(LogLevel level, const char* message) {LogManager* manager = instance->manager;if (level < manager->level) {return;}char time_str[20];get_current_time_string(time_str, sizeof(time_str));pthread_mutex_lock(&manager->lock);fprintf(manager->file, "[%s] ", time_str);switch (level) {case LOG_LEVEL_DEBUG:fprintf(manager->file, "[DEBUG] ");break;case LOG_LEVEL_INFO:fprintf(manager->file, "[INFO] ");break;case LOG_LEVEL_WARN:fprintf(manager->file, "[WARN] ");break;case LOG_LEVEL_ERROR:fprintf(manager->file, "[ERROR] ");break;case LOG_LEVEL_FATAL:fprintf(manager->file, "[FATAL] ");break;}fprintf(manager->file, "%s\n", message);fflush(manager->file);	// 将写缓存区立即写入磁盘。pthread_mutex_unlock(&manager->lock);
}// 设置日志级别函数
void set_log_level(LogLevel level) {instance->manager->level = level;
}init_instance() {instance = (LogManagerSingleton*)malloc(sizeof(LogManagerSingleton));instance->manager = (LogManager*)malloc(sizeof(LogManager));instance->manager->file = fopen("log.txt", "a");instance->manager->level = LOG_LEVEL_INFO;	// 日志默认级别INFOpthread_mutex_init(&instance->manager->lock, NULL);
}// 获取日志管理器单例对象函数
LogManager* get_log_manager_instance() {return instance->manager;
}int main() {init_instance();	/* 程序一开始,就必须执行。不然,与懒汉式无较大差异。 */LogManager* manager = get_log_manager_instance(); // 获取日志管理器单例对象set_log_level(LOG_LEVEL_DEBUG); // 设置日志级别为DEBUGwrite_log(LOG_LEVEL_DEBUG, "debug message"); // 写DEBUG级别日志write_log(LOG_LEVEL_INFO, "info message"); // 写INFO级别日志write_log(LOG_LEVEL_WARN, "warn message"); // 写WARN级别日志write_log(LOG_LEVEL_ERROR, "error message"); // 写ERROR级别日志write_log(LOG_LEVEL_FATAL, "fatal message"); // 写FATAL级别日志fclose(manager->file); // 关闭日志文件pthread_mutex_destroy(&manager->lock); // 销毁互斥锁free(manager); // 释放日志管理器内存free(instance); // 释放日志管理器单例对象内存return 0;
}/*
该示例代码中,使用了单例模式来创建日志管理器对象,保证了整个程序中只有一个日志管理器对象。
日志管理器中包含了日志文件指针、日志级别、互斥锁等成员,通过这些成员来实现日志的写入和级别控制。
在主函数中,设置了日志级别为DEBUG,并写入了5条不同级别的日志,最后关闭日志文件、销毁互斥锁、释放内存。
*/

C语言单例模式-实现高性能配置管理器

代码中,使用了单例模式来创建配置管理器对象,保证了整个程序中只有一个配置管理器对象。配置管理器中包含了配置项数组、配置项数量、互斥锁等成员,通过这些成员来实现配置文件的读取和配置项的获取。在主函数中,获取了一个配置项的值,并打印出来,最后销毁互斥锁、释放内存。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>#define MAX_CONFIG_SIZE 1024// 配置项结构体
typedef struct {char* key; // 配置项键char* value; // 配置项值
} ConfigItem;// 配置管理器结构体
typedef struct {ConfigItem* items; // 配置项数组int count; // 配置项数量pthread_mutex_t lock; // 互斥锁
} ConfigManager;// 配置管理器单例结构体
typedef struct {ConfigManager* manager; // 配置管理器指针
} ConfigManagerSingleton;static ConfigManagerSingleton* instance = NULL; // 配置管理器单例对象指针// 读取配置文件函数
void read_config_file(const char* filename) {ConfigManager* manager = instance->manager;FILE* file = fopen(filename, "r");if (file == NULL) {return;}char line[MAX_CONFIG_SIZE];while (fgets(line, sizeof(line), file) != NULL) {char* key = strtok(line, "=");char* value = strtok(NULL, "\n");if (key != NULL && value != NULL) {ConfigItem item;item.key = strdup(key);item.value = strdup(value);pthread_mutex_lock(&manager->lock);manager->items[manager->count++] = item;pthread_mutex_unlock(&manager->lock);}}fclose(file);
}// 获取配置项值函数
const char* get_config_value(const char* key) {ConfigManager* manager = instance->manager;for (int i = 0; i < manager->count; i++) {if (strcmp(manager->items[i].key, key) == 0) {return manager->items[i].value;}}return NULL;
}// 获取配置管理器单例对象函数
ConfigManager* get_config_manager_instance() {if (instance == NULL) {instance = (ConfigManagerSingleton*)malloc(sizeof(ConfigManagerSingleton));instance->manager = (ConfigManager*)malloc(sizeof(ConfigManager));instance->manager->items = (ConfigItem*)malloc(sizeof(ConfigItem) * MAX_CONFIG_SIZE);instance->manager->count = 0;pthread_mutex_init(&instance->manager->lock, NULL);read_config_file("config.txt");}return instance->manager;
}int main() {ConfigManager* manager = get_config_manager_instance(); // 获取配置管理器单例对象const char* value = get_config_value("key1"); // 获取配置项值if (value != NULL) {printf("key1=%s\n", value);}pthread_mutex_destroy(&manager->lock); // 销毁互斥锁free(manager->items); // 释放配置项数组内存free(manager); // 释放配置管理器内存free(instance); // 释放配置管理器单例对象内存return 0;
}

http://www.ppmy.cn/news/39626.html

相关文章

GP03丨宽窄基资金管理增强策略

量化策略开发&#xff0c;高质量社群&#xff0c;交易思路分享等相关内容 正 文 大家好&#xff0c;今天我们分享股票社群第3期量化策略——ETF资金管理增强策略。 在上一期中&#xff0c;我们分享了基础版ETF轮动&#xff08;结合股票多因子排序逻辑&#xff09;策略&#xf…

免费好用的oa系统有哪些?盘点这几款!

免费好用的oa系统有哪些&#xff1f;盘点这几款&#xff01; 办公自动化&#xff08;OA&#xff09;&#xff0c;英文Office Automation的缩写。它可以通过特定流程或特定环节与日常事务联系在一起&#xff0c;使公文在流转、审批、发布等方面提高效率&#xff0c;实现办公管理…

C++从0到1实战

持续更新中… 1、Windows开发环境的准备 2、第一个C程序 3、C中输出数据 4、C中程序的注释 5、C中变量使用 6、C中常量使用 7、C中标识符的命名 8、C中数据输入 9、C中算术运算 10、C中自增和自减 11、C中赋值运算 12、C11初始化赋值 13、C中关系运算 14、C中逻辑运算 15、C中运…

百度研发效能从度量到数字化蜕变之路

y研发 作者 | 乌拉 导读 企业降本增效的诉求越发强烈&#xff0c;研发效能成为近来极为火爆的话题&#xff0c;本文从效能分析整体思路、实践案例、技术实现介绍了如何从效能度量逐步演变形成基于价值的数字化决策系统的过程&#xff0c;通过本文可以了解到&#xff1a; 1、研…

Android 手机自动化测试工具有哪几种?

一、Android手机自动化测试工具&#xff0c;常用的有这7中&#xff1a; 1、首推Appium&#xff1a; 推荐理由&#xff1a;功能非常强大的移动端自动化测试框架&#xff0c;还免费 下载链接&#xff1a;Appium: Mobile App Automation Made Awesome. Appium是一种被广泛使用的…

数据结构之(三):队列

队列初体验之数组实现方式队列 1、初识队列 队列&#xff0c;是一种对存取有严格要求的数据结构 只能从尾部存入数据&#xff0c;从头部取出数据 遵循“先进先出”原则 队列的实现有两种方式&#xff1a; 顺序队列&#xff08;基于数组&#xff09;、链队列&#xff08;基于链表…

Maven项目中的依赖出现版本冲突,最终发现是对Dependency Scope理解有误

再来个文章目录 文章目录背景疑问排查过程问题存在的原因总结示例依赖版本说明本文记录一下遇到maven依赖版本冲突后的排查过程说明以及问题原因说明 下面还有投票&#xff0c;帮忙投个票&#x1f44d; 背景 最近加入了 Apache Dubbo 开源社区&#xff0c;成为了一名Dubbo Con…

多臂高分子PEG试剂:4Arm PEG L-Lysine,四臂PEG L赖氨酸,4臂聚乙二醇衍生物

一、基础产品数据&#xff1a; 中文名&#xff1a;四臂-PEG L-赖氨酸&#xff0c;四臂聚乙二醇L-赖氨酸&#xff0c;四臂L-赖氨酸PEG 英文名&#xff1a;4 Arm PEG L-Lysine&#xff0c;4-Arm PEG-L-Lysine 二、详细产品数据&#xff1a; 分子量&#xff1a;1k&#xff0c;2k&…