栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

多线程下的初始化技巧及组件设计

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

多线程下的初始化技巧及组件设计

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

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

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方法中不断比较超时即可。

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

全文毕!感谢大家阅读!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/693019.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号