看了第一篇文章,多线程系列,看到了在线程执行任务队列有了一定的了解~!

那么今天我来讲讲,怎么样构建通用的自定义线程概念!

线程执行任务,肯定要有目标,但是如果写死了,那么一个线程处理执行职能按照思路处理一类任务,显然不满足我们的实际场景的需求,那么怎么才能创建灵活的线程执行器呢!

首先我们来创建一个任务构造器!

   /// <summary>
     /// 线程模型执行任务 基类
     /// </summary>
     public abstract class BaseTask
     {

         /// <summary>
         /// 任务ID
         /// </summary>
         public long TID { get; set; }

         /// <summary>
         /// 任务名称
         /// </summary>
         public string TName { get; set; }

         /// <summary>
         /// 线程模型任务
         /// </summary>
         public abstract void Run();

         public override string ToString()
         {
             return "Task<" + this.TName + "(" + TID + ")>";
         }
     }

看到这里,可能不会明白,这么写法的意义在哪里呢?

那么我们再来自定义线程的执行器

 /// <summary>
     /// 定义自定义线程模型
     /// </summary>
     public abstract class BaseThread<T> where T : BaseTask
     {
         //执行线程
         Thread _Thread;
         //通知一个或多个正在等待的线程已发生事件
         ManualResetEvent mre = new ManualResetEvent(false);
         //线程安全的队列
         System.Collections.Concurrent.ConcurrentQueue<T> cqueue = new System.Collections.Concurrent.ConcurrentQueue<T>();

         /// <summary>
         /// 自定义线程ID;
         /// </summary>
         public long TID { get; set; }

         public static bool IsRuning = true;

         /// <summary>
         /// 初始化
         /// </summary>
         /// <param name="tName">线程的名称</param>
         public BaseThread(string tName)
         {
             _Thread = new Thread(Runing);
             _Thread.Name = tName;
             _Thread.Start();
         }

         //模拟新增任务
         public void AddTask(T task)
         {
             //添加任务到队列
             cqueue.Enqueue(task);
             //唤醒所有相关的挂起线程
             mre.Set();
         }

         void Runing()
         {
             //主循环 服务器运行标识
             while (IsRuning)
             {
                 //如果是空则继续等待      服务器运行标识
                 while (cqueue.IsEmpty && IsRuning)
                 {
                     //重置线程暂停状态
                     mre.Reset();
                     //这个操作是以便服务器需要停止操作,
                     //如果停止调用线程的Thread.Abort()是会导致处理队列任务丢失
                     mre.WaitOne();
 #if DEBUG
                     //为了方便测试信息打印的暂停信息
                     Console.WriteLine(DateTime.Now.ToString("HH:mm:ss:ffff") + " : " + Thread.CurrentThread.Name + " Status Sleep");
 #endif
                 }
                 T t;
                 //取出队列任务
                 if (cqueue.TryDequeue(out t))
                 {
                     Runing(t);
                 }
             }
         }

         /// <summary>
         /// 设置运行方法为虚方法,方便子函数覆盖
         /// </summary>
         protected virtual void Runing(T run)
         {
             try
             {
                 //执行任务
                 run.Run();
                 //打印任务信息
                 Console.WriteLine(DateTime.Now.ToString("HH:mm:ss:ffff") + " : " + Thread.CurrentThread.Name + " Action:" + run.ToString());
             }
             catch (Exception ex)
             {
                 //打印任务信息
                 Console.WriteLine(DateTime.Now.ToString("HH:mm:ss:ffff") + " : " + Thread.CurrentThread.Name + " Action:" + run.ToString() + " Exception:" + ex);
             }
         }
     }

看到这里是不是比较清楚了?这样我们定义的线程是不是能完成多不同类型的任务呢?

是不是可以做到一个线程执行和处理不同类型的任务呢?

接下来我们创建类型的实现类

任务实现类1

 /// <summary>
     /// 测试任务
     /// </summary>
     public class TestTask : BaseTask
     {

         public override void Run()
         {
             Console.WriteLine("我只是用来测试的");
         }
     }

任务实现类2

 public class TestTask1 : BaseTask
     {

         /// <summary>
         /// 执行任务
         /// </summary>
         public Action Test { get; set; }

         public override void Run()
         {
             if (Test != null)
             {
                 Test();
             }
             Console.WriteLine("我只是用来测试的");
         }
     }

线程的实现类

     /// <summary>
     /// 测试线程
     /// </summary>
     public class TestThread : BaseThread<BaseTask>
     {
         public TestThread()
             : base("TestThread")
         {

         }
     }

接下来我们看看测试效果

     class Program
     {

         static void Main(string[] args)
         {
             TestThread tt = new TestThread();
             tt.AddTask(, TName = "测试1" });
             tt.AddTask(, TName = "测试2" });
             tt.AddTask(, TName = ); }) });
             tt.AddTask(, TName = "测试4" });
             Console.ReadLine();
         }
     }

运行结果图

看到这里是不是很清楚明了呢?这样我们在处理日常任务的时候,不同类型的逻辑或者任务类型,是不是都可以放到一个线程执行呢?

请大家期待我的下一篇文章,为大家讲解,定时器线程执行器,

c# 多线程系列二 自定义线程执行器的更多相关文章

  1. (Java多线程系列二)线程间同步

    Java多线程间同步 1.什么是线程安全 通过一个案例了解线程安全 案例:需求现在有100张火车票,有两个窗口同时抢火车票,请使用多线程模拟抢票效果. 先来看一个线程不安全的例子 class Sell ...

  2. java多线程系列(二)

    对象变量的并发访问 前言:本系列将从零开始讲解java多线程相关的技术,内容参考于<java多线程核心技术>与<java并发编程实战>等相关资料,希望站在巨人的肩膀上,再通过我 ...

  3. java多线程系列(二)---对象变量并发访问

    对象变量的并发访问 前言:本系列将从零开始讲解java多线程相关的技术,内容参考于<java多线程核心技术>与<java并发编程实战>等相关资料,希望站在巨人的肩膀上,再通过我 ...

  4. java多线程编程(二创建线程)

    1.概念           因为java是完全面向对象的,所以在java中,我们说的线程,就是Thread类的一个实例对象.所以,一个线程就是一个对象,它有自己字段和方法. 2.创建线程 创建线程有 ...

  5. Java多线程(二) —— 线程安全、线程同步、线程间通信(含面试题集)

    一.线程安全 多个线程在执行同一段代码的时候,每次的执行结果和单线程执行的结果都是一样的,不存在执行结果的二义性,就可以称作是线程安全的. 讲到线程安全问题,其实是指多线程环境下对共享资源的访问可能会 ...

  6. java多线程(四)-自定义线程池

    当我们使用 线程池的时候,可以使用 newCachedThreadPool()或者 newFixedThreadPool(int)等方法,其实我们深入到这些方法里面,就可以看到它们的是实现方式是这样的 ...

  7. java多线程(二)-线程的生命周期及线程间通信

    一.摘要    当我们将线程创建并start时候,它不会一直占据着cpu执行,而是多个线程间会去执行着这个cpu,此时这些线程就会在多个状态之间进行着切换. 在线程的生命周期中,它会有5种状态,分别为 ...

  8. java多线程系列六、线程池

    一. 线程池简介 1. 线程池的概念: 线程池就是首先创建一些线程,它们的集合称为线程池. 2. 使用线程池的好处 a) 降低资源的消耗.使用线程池不用频繁的创建线程和销毁线程 b) 提高响应速度,任 ...

  9. Java 多线程(二)—— 线程的同步

     上文创建多线程买票的例子中注释会出现错票.重票的问题,本文来讲讲如何解决此问题.本文例子:利用多线程模拟 3 个窗口卖票 实现Runnable接口 public class TestThread2 ...

随机推荐

  1. Intellij IDEA Java web 项目搭建

    Java web 项目搭建 简介 在上一节java web环境搭建中,我们配置了开发java web项目最基本的环境,现在我们将采用Spring MVC+Spring+Hibernate的架构搭建一个 ...

  2. 微软Connect教程系列—VS2015集成新潮工具(四)

    本课程来源与微软connect视频教程,Modern Web Tooling in Visual Studio 2015 本课程主要讲下当下流行的前端工具 bower和grunt 首先简单介绍下这俩货 ...

  3. 字符串混淆技术在.NET程序保护中的应用及如何解密被混淆的字符串

    Visual Studio提供的Dotfuscator保护程序,可以对用户代码中包含的字符串进行加密.比如下面的例子,为了找到这个程序的注册算法,用.NET Reflector加载程序集后,发现代码中 ...

  4. 从KRE到XRE:ASP.NET 5中正在消失的那些K

    前几天写了篇博客ASP.NET 5中的那些K,刚把ASP.NET 5中的那些K搞明白了些,昨天发现微软正在让那些K消失. 首先是在 KRuntime 的git日志中发现的: * Runtime ren ...

  5. Emberjs之ComputedProperty

    计算属性,以下简称CP.简单概括来讲,就是在需要属性值的时候计算一个Function,并将Function返回的值保存在属性中,当第二次获取属性值时,如果发现属性并未改变则直接读取属性,如果属性依赖的 ...

  6. 关于RPC与MQ异同的理解

    最近看了一些资料,回顾过去项目的经验,梳理自己对两者异同的理解: 相同: 1.都利于大型系统的解耦: 2.都提供子系统之间的交互,特别是异构子系统(如java\node等不同开发语言): 不同: 1. ...

  7. ECMAScript 6 简介

    ECMAScript 6 是JavaScript的下一个标准,正处在快速开发之中,大部分已经完成了,预计将在2014年正式发布.Mozilla将在这个标准的基础上,推出JavaScript 2.0. ...

  8. 如何让Hadoop读取以gz结尾的文本格式的文件

    背景: 搜索引擎在build全量时,会产生数G的xml的中间文件,我需要去查询这些中间文件中,是否有某个特殊的字符.xml文件有很多,每个都有几百M,存储在hdfs上,而且是以gz结尾的文本格式的文件 ...

  9. 通过分析iframe和无阻塞脚本关系能让我们更懂iframe

    在我上篇文章里,我提到一种使用iframe完成无阻塞脚本加载的方式,因为我对iframe的偏见很大,所以上篇文章里我没有展开讨论这个问题. 文章发表后有位网友问了我这样一个问题,下面是他问题的原文,如 ...

  10. Winform文件下载之断点续传

    在本系列的前两篇文章中,分别向大家介绍了用于完成下载任务的 WebClinet 和 WinINet 的基本用法和一些实用技巧. 今天来为大家讲述下载过程中最常遇到的断点续传问题. 首先明确一点,本文所 ...