功能描述:

  1. 支持创建多个线程池,并统一管理
  2. 支持不同线程池的容量控制,以及最少活动线程的设置
  3. 支持不同线程池中活动线程的闲时设置,即线程空闲时间到期后即自动被回收

结构设计:

  • ThreadWorkerPoolManager: 线程池管理器,用于统一创建,获取,销毁线程池,使用单例模式
  • ThreadWorkerPool: 线程池,用于管理指定数量的线程,由ThreadWorkerPoolManager管理,自身无法创建与销毁
  • TheadWorkerPoolItem: 线程池项,用于包装线程工作器,协助ThreadWorkerPool更好的管理线程,例如取出,放回,闲时的控制
  • TheadWorker: 线程工作器,用于包装系统线程System.Threading.Thread,使其可以重复使用,减少Thrad创建和销毁的性能开销

  结构关系图:

  

 详细设计:

  ThreadWoker

  要点设计:

  1. 完成一次任务后,System.Threading.Thread不能被系统销毁, 默认情况下new Thread(ThreadStart start).Start(), 当ThreadStart委托的任务完成后,系统将销毁该线程,也就是说创建一个System.Threading.Thread实例只能使用一次;为了使线程能被重复使用,ThreadWoker将使用 while+sleeping 的方式对系统线程进行包装,同时使用AutoResetEvent代替Thread.Sleep(timeout)来达到更佳的控制
  2. 闲时设计,线程资源是极其宝贵的系统资源,如果线程池中存在大量的空闲线程这是一种浪费,极端情况下将影响系统的稳定性和工作效率;ThreadWorker将使用AutoResetEvent和事件通知的方式来代替在线程池中定期轮询检查的方式,每完成一个任务将重新开始空闲时间的计算,如果ThreadWorker在线程池中被取出,那么ThreadWorker空闲时间将永远不会到期,直到ThreadWorker被返回线程池后才重新开始空闲时间的计算

  状态图:

  

  关键代码:

  

         private void ThreadWorking()
{
while (_status != ThreadWorkerStatus.Abort)
{
//WaitOne 返回false表示等待超时,true接到取消等待的通知
//这里利用AutoResetEvent.WaitOne的特性来设计闲时控制,false表示空闲到期,true表示新的任务开始
if (!_waitEvent.WaitOne(_idleTime))
{
if (!_isCanIdleExpired) //_isCanIdleExpired变量控制是否允许超时,例如被取出后将不能超时
continue; _status = ThreadWorkerStatus.Abort;
_waitEvent.Close();
_waitEvent.Dispose();
if (OnIdleExpired != null)
OnIdleExpired(this, null); //空闲到期事件通知
return;
}
else if (_status == ThreadWorkerStatus.Abort)
return; try
{
Working();
}
catch (Exception ex)
{
_logger.TraceEvent(TraceEventType.Error, (int)TraceEventType.Error, ex.ToString());
}
finally
{
_status = ThreadWorkerStatus.Idle;
if (OnWorkCompleted != null)
OnWorkCompleted(this, null); //任务完成事件通知
}
}
}
      public void Work()
{
if (_status == ThreadWorkerStatus.Abort)
throw new InvalidOperationException("this ThreadWorker was Abort!"); if (_status == ThreadWorkerStatus.Working)
throw new InvalidOperationException("this ThreadWorker was working, unable to duplicate work!"); _status = ThreadWorkerStatus.Working;
_waitEvent.Set(); //通知线程有个新的工作要开始
}

  ThreadWorkerPoolItem

  要点设计:

  1. 链接ThreadWorker和线程池,线程池通过ThreadWorkerPoolItem控制ThreadWorker在线程池的取出,放回,销毁
  2. 通过订阅ThreadWorker的空闲到期事件OnIdleExpired,来完成线程池对线程的移除
  3. 通过订阅ThreadWorker的任务完成事件OnWorkCompleted,来完成线程返回线程池的操作
  4. 提供剩余空闲时间查询,来为线程池提供更优线程取出方案

  完整代码:

     public sealed class ThreadWorkerPoolItem
{
private ThreadWorkerPoolItemStatus _status;
private readonly ThreadWorkerBase _threadWorker;
private readonly ThreadWorkerPoolBase _threadWorkerPool;
private readonly int _idleTime;
private DateTime _startIdleTime; internal ThreadWorkerPoolItem(ThreadWorkerPoolBase pool, ThreadWorkerBase threadWorker, ThreadWorkerPoolSettings poolSettings)
{
_threadWorkerPool = pool;
_threadWorker = threadWorker;
_threadWorker.OnIdleExpired += _threadWorker_OnIdleExpired;
_threadWorker.OnWorkCompleted += _threadWorker_OnWorkCompleted;
_threadWorker.Start();
_status = ThreadWorkerPoolItemStatus.Idle;
_idleTime = poolSettings.IdleTime;
} void _threadWorker_OnWorkCompleted(object sender, EventArgs args)
{
_threadWorkerPool.Return(this);
} void _threadWorker_OnIdleExpired(object sender, EventArgs args)
{
_threadWorkerPool.Remove(this);
} internal ThreadWorkerPoolItemStatus Status
{
get
{
if (_threadWorker.Status == ThreadWorkerStatus.Abort || _status == ThreadWorkerPoolItemStatus.Abort)
return ThreadWorkerPoolItemStatus.Abort; return _status;
}
} internal int SurplusIdleTime
{
get
{
if (_status == ThreadWorkerPoolItemStatus.Take || _idleTime == -)
return -; int idledTime = (int)(_startIdleTime - DateTime.Now).TotalMilliseconds;
if (idledTime >= _idleTime)
return ; return idledTime;
}
} internal void SetTake()
{
_threadWorker.IsCanIdleExpried = false;
_status = ThreadWorkerPoolItemStatus.Take;
} internal void SetIdle()
{
_startIdleTime = DateTime.Now;
_status = ThreadWorkerPoolItemStatus.Idle;
_threadWorker.IsCanIdleExpried = true;
} internal ThreadWorkerBase ThreadWorker
{
get { return _threadWorker; }
}
}

  ThreadWorkerPool

  要点设计:

  1. 使用Lock配合ThreadWorkerPoolItem的状态来确保多线程下,每次取出的都是空闲的ThreadWorker
  2. 取出的超时设计,由于线程池有容量控制,高并发下必然导致线程池满负荷,提供超时设置,有利于使用者自行控制满负荷情况下的处理;ThreadWorkerPool将使用while+sleeping的方式,同时使用AutoResetEvent代替Thread.Sleep(timeout)来达到更佳的控制,当一个线程被放回线程池时,另一等待获取者立即获取,而无需等待下一次轮询的到来

  关键代码:

         protected bool TryTake(int timeout, out ThreadWorkerBase threadWorker)
{
threadWorker = null;
lock (_takeLocker)
{
ThreadWorkerPoolItem worker = null;
DateTime startWaitTime;
while (!_isDestoryed)
{
worker = _threadWorkerList.Where(e => e.Status == Core.ThreadWorkerPoolItemStatus.Idle).OrderByDescending(e => e.SurplusIdleTime).FirstOrDefault();
if (worker == null)
{
if (_threadWorkerList.Count < _settings.MaxThreadWorkerCount)
{
worker = this.CreatePoolItem(_threadWorkerList.Count + , _settings.IdleTime);
worker.SetTake();
_threadWorkerList.Add(worker);
threadWorker = worker.ThreadWorker;
return true;
} startWaitTime = DateTime.Now;
if (!_takeWaitEvent.WaitOne(timeout))
{
threadWorker = null;
return false;
} if (timeout != -)
{
timeout = timeout - (int)(DateTime.Now - startWaitTime).TotalMilliseconds;
if (timeout <= )
{
threadWorker = null;
return false;
}
}
continue;
} threadWorker = worker.ThreadWorker;
worker.SetTake();
return true;
} threadWorker = null;
return false;
}
}
         internal void Return(ThreadWorkerPoolItem item)
{
item.SetIdle();
_takeWaitEvent.Set();
}

  ThreadWorkerPoolManager使用单例模式管理,代码过于简单这里就不贴了......

  有兴趣的同学可以点击这里进行下载源码查看:Nutshell.ThreadWorkerPool.zip

  github 开源地址: https://github.com/zcylife/Nutshell

Nutshell.ThreadWorkerPool .Net线程池设计的更多相关文章

  1. Net线程池设计

    Net线程池设计 功能描述: 支持创建多个线程池,并统一管理 支持不同线程池的容量控制,以及最少活动线程的设置 支持不同线程池中活动线程的闲时设置,即线程空闲时间到期后即自动被回收 结构设计: Thr ...

  2. 【转载】深度解读 java 线程池设计思想及源码实现

    总览 开篇来一些废话.下图是 java 线程池几个相关类的继承结构: 先简单说说这个继承结构,Executor 位于最顶层,也是最简单的,就一个 execute(Runnable runnable) ...

  3. Java并发指南12:深度解读 java 线程池设计思想及源码实现

    ​深度解读 java 线程池设计思想及源码实现 转自 https://javadoop.com/2017/09/05/java-thread-pool/hmsr=toutiao.io&utm_ ...

  4. Java - 线程池设计与选择

    http://ifeve.com/how-to-calculate-threadpool-size/ 任务一般可分为:CPU密集型.IO密集型.混合型,对于不同类型的任务需要分配不同大小的线程池. C ...

  5. 谈谈Java的线程池设计

    在实际项目中,如果因为想异步执行暂时性的任务而不断创建线程是很浪费资源的事情(当一个任务执行完后,线程也没用了).这种情况下,最好是将任务提交给线程池执行. 所谓池,就是将管理某一种资源,对资源进行复 ...

  6. 分享一个自制的 .net线程池

    扯淡 由于项目需求,需要开发一些程序去爬取一些网站的信息,算是小爬虫程序吧.爬网页这东西是要经过网络传输,如果程序运行起来串行执行请求爬取,会很慢,我想没人会这样做.为了提高爬取效率,必须使用多线程并 ...

  7. 线程池原理及创建(C++实现)

    http://www.cnblogs.com/lidabo/p/3328402.html 本文给出了一个通用的线程池框架,该框架将与线程执行相关的任务进行了高层次的抽象,使之与具体的执行任务无关.另外 ...

  8. 线程池原理及创建并C++实现

    本文给出了一个通用的线程池框架,该框架将与线程执行相关的任务进行了高层次的抽象,使之与具体的执行任务无关.另外该线程池具有动态伸缩性,它能根据执行任务的轻重自动调整线程池中线程的数量.文章的最后,我们 ...

  9. C#的线程池的那些事

    最近在做站时发现,线程池的问题很棘手,所以总结了一篇关于线程池的文章,原文地址:http://www.shuonar.com/blog/ac16496b-87ec-4790-a9ea-d69bbffa ...

随机推荐

  1. 理解java的三大特性之多态(三)

    摘自:http://cmsblogs.com/?p=52 面向对象编程有三大特性:封装.继承.多态. 封装隐藏了类的内部实现机制,可以在不影响使用的情况下改变类的内部结构,同时也保护了数据.对外界而已 ...

  2. 【Beta】Phylab2.0: Postmortem

    设想和目标 1. 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 主要解决同学们写物理实验报告时,处理数据的困难--巨大的计算量和不规范的物理报告数据处理格式.典型 ...

  3. cf C. Dima and Containers

    http://codeforces.com/contest/358/problem/C 将最大的放在stack里面,第二大的放在queue中,第三大的放在deck里面.然后模拟就可以了. #inclu ...

  4. Visio 下载,及密钥

    Visio2010简体中文高级版(永久激活密钥:GR24B-GC2XY-KRXRG-2TRJJ-4X7DC) ed2k://|file|cn_visio_2010_x64_516562.exe|515 ...

  5. to_char函数引发的不走索引

    SQL> conn cowork_czsh/cowork_czsh Connected. SQL> set linesize 200 SQL> set pagesize 200 SQ ...

  6. jquery点击按钮显示和隐藏DIv

    function changeDisplay() { if ($("#btnShow").attr("value")== "添加附件") { ...

  7. JFrame编程

    最基础的窗口 public test1() { setTitle("test1"); setSize(300,300); //设置窗口大小 setLocation(300,300) ...

  8. PHP null常量和null字节的区别

    在学习isset()时,看到了这句话:“如果已经使用 unset() 释放了一个变量之后,它将不再是 isset().若使用 isset() 测试一个被设置成 NULL 的变量,将返回 FALSE.同 ...

  9. C/C++基础概念

    1.类占用的内存大小: 1)在不同位数的操作系统下,各种数据类型所占用的内存大小:32位和64位操作系统 http://blog.csdn.net/b_zhang/article/details/68 ...

  10. 为人们服务的asp.net 验证控件

    ASP.NET是微软推出的WEB开发工具,他有很强大的功能,今天看视频讲到验证控件这一部分,真的感受到了微软全心全意为人民服务了.越来越佩服微软了,人家都设计出来了,咱们一定要会用才可以啊,不然太…. ...