IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 多线程下的初始化技巧及组件设计 -> 正文阅读

[Java知识库]多线程下的初始化技巧及组件设计

在日常开发中,我们会遇到很多场景,不同的场景有不同的设计实现思路,其实很多时候看似简单的原理,反而很有价值。就像解决活锁的问题那样,最后解决方案是设置不同的超时时间即可。

当服务启动后,需要等待某个线程完成初始化,这种场景比较场景,类似于生产者消费者模型的事件通知。
但是这种场景下,只需要一次信号通知即可。当然了,这种实现方式比较多,我们先用一种最简单的方式去模拟实现一下。

1、案例

这里假设有个RedisServer的类,这个类是一个线程,将初始化并完成全局参数的加载。然后启动其他业务线程开始正常运行,如下面的示例代码中,Launch方法将启动线程,线程的入口是本类中的onRedisTask方法。

Class RedisServer
{
    public:
        int Init(); //初始化
        void Launch(); //启动线程
        static void onRedisTask(void* para); //启动线程的入口
   public:
       bool is_started = false;
};

在程序启动的过程中,首先需要完成RedisService的创建和初始化,然后启动任务。当RedisService完成数据的加载,则修改is_started变量为true,主线程中的示意代码如下。

......
RedisServer* pService = new RedisServer;
if(pService && pService ->Init()  == 0)
     pService ->Launch();
else 
    return;
qhile(!pService ->is_started); //等待Redis初始化完成
//其他业务线程再初始化,启动……
.......

上面的场景和设计比较简单,但是也适用于很多的业务系统。

2、组件设计

那么我们要思考一下,能不能提取设计一个小的通用化组件,将来可以应对
一对多的初始化,也可以应对多对一的初始化场景呢?答案是肯定可以的,接下来我们先简单介绍如何实现。

class CEvent
{
public:
    CEvent() {g_count = 0;};
    ~CEvent() = default;
    void Require(){ __sync_add_and_fetch(&(g_count), 1);};
    void Release(){ __sync_add_and_fetch(&(g_count), -1);};
    void Wait(){ while (g_count == 0); };
private:
    int g_count;
};

上面的类CEvent中,其实就是通过Require方法进行原子操作加1。通过Release方法进行原子减一操作。关于CAS的原子命令,后面我将单独 写篇文章介绍。那么如何使用CEvent类呢?我们一起来看看。

class TaskService_A
{
 public:
    int Init(Event& event)
    {
         event.Require(); //请求一次
         //执行其他事情
    };
    void Run() 
    {
        do_Before();
        event.Release(); //释放一次
        while(true){ .... }
        do_after();
    }
}

在mian线程中将这样使用,请看下面的参考代码。

//main线程中
......
CEvent event;
//启动线程A
TaskService_A* pTaskA = new TaskService_A;
pTaskA->Init(event);
pTaskA->Launch();
//启动线程B
TaskService_A*pTaskB = new TaskService_A;
pTaskB->Init(event);
pTaskB->Launch();
.....省略其他代码.....
event.wait(); //等待其他任务初始化完成

上面的套路是不是很简单,熟悉吗?这就是锁的机制,当申请锁的时候,其实是引用加1,释放锁的时候引用减一。

3、总结

另外,既然谈到了多线程,在多线程下,回收线程也是一个很重要的事情,linux下有waitpid等函数回收操作。c++中也有Joinable函数,等待线程回收。那么我们也可以通过上面CEvenet的方式,主线程最终阻塞在event.wait方法上,等其他线程收到退出信号,退出后减掉1次,最终也可以实现线程的回收,明白这种设计思路即可,在实际开发中,还可以设置超时时间,其实就是在初始化的时候记录下时间戳,最终等待的时候,wait方法中不断比较超时即可。

正所谓,原理和设计思想都是通用的,这才是我们成长的基本功,也希望大家多积累,总结并完善自己的知识体系。

全文毕!感谢大家阅读!

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-01-01 13:44:53  更:2022-01-01 13:45:23 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:39:49-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码