自己实现一个“线程池”

本文介绍了线程池的实现与使用。因创建和释放线程会消耗系统资源,故使用线程池可节省资源。实现步骤包括创建装线程的容器、判断线程状态的机制,定制线程类配合使用。最后演示了线程池对象的创建、线程添加及获取空闲线程的操作。

今天见论坛里有问怎么样实现线程池。碰巧原来写过一个类似的。现在来说说。(下面的全是个人理解,不见得是正确的。)

1。先来说说线程池。为什么要使用线程池?
因为创建线程和释放线程是要消耗系统资源的,如果要完成一个工作要不停的创建和释放线程必然会造成很大的系统资源的浪费,所以用线程池。在线程本次工作完成后,不释放线程,让线程等待。再有需要让线程去完成的工作时就把原来创建的线程取过来继续使用。这样节省了重复的创建释放线程的过程。

2。如何实现功能。
根据上面的理解我们来实现这些工作。
A.我们先要创建一个容器来装这些已经创建的线程。
B.然后我们需要用一套机制来让我们知道容器中的线程哪个是空闲的。哪个正在工作。

开始动手写吧.
//.h文件
#ifndef MyThreadPoolH
#define MyThreadPoolH
#include <Classes.hpp>
//定义通讯消息
#define TP_AddThread        WM_USER + 1001 //向容器添加一个线程
#define TP_DeleteThread     WM_USER + 1002 //删除容器中的一个线程
#define TP_GetFreeThread    WM_USER + 1003 //获取一个空闲线程
#define TP_GetThreadCount   WM_USER + 1004 //得到容器中的线程总数

class MyThreadPool : public TObject
{
private:
    HANDLE FHandle;//线程池的句柄 用来接收通讯消。
    TList *FThreadList; //用一个TList来做容器
    bool FError; //是否出现错误
    void __fastcall (TMessage &Message);//消息处理函数
    long __fastcall FGetThreadCount(void);//得到容器中线程的总数
public:
    __fastcall MyThreadPool();
    __fastcall ~MyThreadPool();
__published:
    //发布属性
    __property HNDLE Handle={read=FHandle};
    __property bool Error={read=FError};
    //__property TList *ThreadList={read=FThreadList};//如果有必要把容器发布出来 !但会降低安全性!
    __property long ThreadCount={read=GetFreeThread};
};
#endif

//.cpp
#include <vcl.h>
#pragma hdrstop

#include "MyThreadPool.h"
#pragma package(smart_init)

__fastcall MyThreadPool::MyThreadPool()
{
    FError=false;
    FHandle=AllocateHWnd(MyProc);//创建一个窗口句柄来处理消息
    if(FHandle==NULL)
    {
        FError=true;
        return;
    }
    FThreadList=new TList;//创建容器
    if(FThreadList==NULL)
    {
        FError=true;
        return;
    }
}
__fastcall MyThreadPool::~MyThreadPool()
{
    if(FHandle!=NULL)//释放句柄
    {
        DeallocateHWnd(FHandle);
    }
    if(FThreadList!=NULL)//释放容器
    {//这里只把容器中的线程指针给删除了。
     //中间的线程并没有释放。要释放需要自己添加代码
        FThreadList->Clear();
        delete FThreadList;
    }
}
//处理消息
void __fastcall MyThreadPool::MyProc(TMessage &Message)
{
    void *pThread;
    int ret;
    switch(Message.Msg)
    {
        case TP_AddThread://添加线程的时候消息的WParam参数为线程指针
            pThread=(void *)Message.WParam;
            ret=FThreadList->Add(pThread);
            Message.Result=ret;//返回线程指针在容器中的index
            return;
        case TP_DeleteThread://删除线程时消息的WParam参数为线程指针
            pThread=(void *)Message.WParam;
            ret=FThreadList->IndexOf(pThread);
            //如果线程指针不在容器中返回-1,成功删除返回1
            if(ret==-1)
            {
                Message.Result=-1;
            }
            else
            {
                FThreadList->Delete(ret);
                Message.Result=1;
            }
            return;
        case TP_GetFreeThread://得到一个空闲的线程,如果有空闲消息返回值为线程指针。
            //一但线程给取出线程的Working属性就倍设置成true;
            for(int i=0;i<FThreadList->Count;i++)
            {
                pThreadFThreadList->Items[i];
                if(((TMyThread *)pThread)->Working==false)
                {
                    ((TMyThread *)pThread)->Working=true;
                    Message.Result=(long)pThread;
                    return;
                }
            }
            Message.Result=0;
            return;
        case TP_GetThreadCount://返回容器中的总数
            Message.Result=FThreadList->Count;
            return;
    }
    try
    {
        Dispatch(&Message);
        if(Message.Msg==WM_QUERYENDSESSION)
        {
            Message.Result=1;
        }
    }
    catch(...){};
}

3。我们还需要定制一个自己的线程类来配合上面的ThreadPool来使用

class TMyThread : public TThread
{
private:
    bool FWorking;
    HANDLE PoolHandle
protected:
    void __fastcall Execute();
public:
    __fastcall TMyThread(bool CreateSuspended,HANDLE hHandle/*线程池的句柄*/);
__published:
    //发布属性
    __property bool Working={read=FWorking,write=FWorking};             //线程是否空闲
};

__fastcall TMyThread::TMyThread(bool CreateSuspended,HANDLE hHandle)
    : TThread(CreateSuspended)
{
    PoolHandle=hHandle;
    FWorking=false;   
}
void __fastcall TMyThread::Execute()
{
    while(!Terminated)
    {
        FWorking=true;
        //工作代码
        //。。。。
        FWorking=false;
  this->Suspend();
    }
    ::SendMessage(PoolHandle,TP_DeleteThread,(long)this,0);//在线程池的容器中删除本线程
    return;//线程结束
}

4。下面来演示一下如何使用
//1.创建线程池对象
MyThreadPool *pMyTP=new MyThreadPool;
if(!pMyTP || pMyTP->Error)
{
    //创建出错。
    //。。。处理代码
}
//2.创建N个TMyThread线程对象,并加入线程池
TMyThread *pThread;
for(int i=0;i<N;i++)
{
    pThread=new TMyThread(true,pMyTP->Handle);
    ::SendMessage(pMyTP->Handle,TP_AddThread,(long)pThread,0);        
}
//3.从线程池中去空闲线程
TMyThread *pThread;
pThread=(TMyThread *)::SendMessage(pMyTP->Handle,TP_GetFreeThread,0,0);
if(pThread)//如果有空闲线程
{
    pThread->Resume();  
}        

这样就大致实现了线程池的功能。这种东西我已经用在了程序里了。效果还不错节省了不少资源。但是可能和书上说的线程池还是有很大差别的。
我们暂且叫它线程池A。反正已经达到我开始的时候设计它的目的,节省了资源。
就当是抛砖引玉吧。希望这些代码能给兄弟们一点启发,对兄弟门有用。

在 Java 中,线程池是一种管理多个线程的机制,可以有效减少线程创建和销毁的开销,提高程序的性能。Java 提供了 `java.util.concurrent` 包来简化线程池的创建和使用,其中 `ExecutorService` 是最常用的接口。 以下是一个使用 `Executors` 工厂类创建线程池的示例: ```java import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ThreadPoolExample { public static void main(String[] args) { // 创建一个固定大小为3的线程池 ExecutorService executorService = Executors.newFixedThreadPool(3); // 提交5个任务给线程池 for (int i = 1; i <= 5; i++) { int taskId = i; executorService.submit(() -> { System.out.println("正在执行任务 " + taskId + ",线程名:" + Thread.currentThread().getName()); try { Thread.sleep(2000); // 模拟任务执行耗时 } catch (InterruptedException e) { e.printStackTrace(); } }); } // 关闭线程池(不再接受新任务,但已提交的任务会继续执行) executorService.shutdown(); } } ``` ### 代码解释: 1. **创建线程池**: - `Executors.newFixedThreadPool(3)` 创建一个固定大小为 3 的线程池。 - 线程池中的线程可以重复利用,避免频繁创建和销毁线程的开销。 2. **提交任务**: - 使用 `executorService.submit()` 方法提交任务。任务可以是一个 `Runnable` 或 `Callable`。 - 每个任务打印当前执行的线程名称,模拟执行耗时的操作。 3. **关闭线程池**: - `executorService.shutdown()` 表示不再接受新任务,但已经提交的任务会继续执行。 - 如果需要立即关闭线程池并尝试中断正在执行的任务,可以使用 `executorService.shutdownNow()`。 ### 自定义线程池(使用 `ThreadPoolExecutor`) 如果你需要更灵活地控制线程池的行为(例如设置最大线程数、空闲线程超时时间等),可以使用 `ThreadPoolExecutor`: ```java import java.util.concurrent.*; public class CustomThreadPoolExample { public static void main(String[] args) { int corePoolSize = 2; int maximumPoolSize = 4; long keepAliveTime = 10; TimeUnit unit = TimeUnit.SECONDS; BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(); // 自定义线程池 ExecutorService executorService = new ThreadPoolExecutor( corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue ); // 提交任务 for (int i = 1; i <= 6; i++) { int taskId = i; executorService.submit(() -> { System.out.println("正在执行任务 " + taskId + ",线程名:" + Thread.currentThread().getName()); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } }); } executorService.shutdown(); } } ``` ### 说明: - `corePoolSize`: 核心线程数,线程池中始终保持的线程数量。 - `maximumPoolSize`: 最大线程数,线程池中允许的最大线程数。 - `keepAliveTime`: 空闲线程的存活时间。 - `unit`: 时间单位。 - `workQueue`: 任务队列,用于存放等待执行的任务。 --- ###
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值