c# 多线程系列二 自定义线程执行器

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

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

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

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

 1   /// <summary>
 2     /// 线程模型执行任务 基类
 3     /// </summary>
 4     public abstract class BaseTask
 5     {
 6
 7         /// <summary>
 8         /// 任务ID
 9         /// </summary>
10         public long TID { get; set; }
11
12         /// <summary>
13         /// 任务名称
14         /// </summary>
15         public string TName { get; set; }
16
17         /// <summary>
18         /// 线程模型任务
19         /// </summary>
20         public abstract void Run();
21
22         public override string ToString()
23         {
24             return "Task<" + this.TName + "(" + TID + ")>";
25         }
26     }

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

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

 1 /// <summary>
 2     /// 定义自定义线程模型
 3     /// </summary>
 4     public abstract class BaseThread<T> where T : BaseTask
 5     {
 6         //执行线程
 7         Thread _Thread;
 8         //通知一个或多个正在等待的线程已发生事件
 9         ManualResetEvent mre = new ManualResetEvent(false);
10         //线程安全的队列
11         System.Collections.Concurrent.ConcurrentQueue<T> cqueue = new System.Collections.Concurrent.ConcurrentQueue<T>();
12
13         /// <summary>
14         /// 自定义线程ID;
15         /// </summary>
16         public long TID { get; set; }
17
18         public static bool IsRuning = true;
19
20         /// <summary>
21         /// 初始化
22         /// </summary>
23         /// <param name="tName">线程的名称</param>
24         public BaseThread(string tName)
25         {
26             _Thread = new Thread(Runing);
27             _Thread.Name = tName;
28             _Thread.Start();
29         }
30
31         //模拟新增任务
32         public void AddTask(T task)
33         {
34             //添加任务到队列
35             cqueue.Enqueue(task);
36             //唤醒所有相关的挂起线程
37             mre.Set();
38         }
39
40         void Runing()
41         {
42             //主循环 服务器运行标识
43             while (IsRuning)
44             {
45                 //如果是空则继续等待      服务器运行标识
46                 while (cqueue.IsEmpty && IsRuning)
47                 {
48                     //重置线程暂停状态
49                     mre.Reset();
50                     //这个操作是以便服务器需要停止操作,
51                     //如果停止调用线程的Thread.Abort()是会导致处理队列任务丢失
52                     mre.WaitOne(2000);
53 #if DEBUG
54                     //为了方便测试信息打印的暂停信息
55                     Console.WriteLine(DateTime.Now.ToString("HH:mm:ss:ffff") + " : " + Thread.CurrentThread.Name + " Status Sleep");
56 #endif
57                 }
58                 T t;
59                 //取出队列任务
60                 if (cqueue.TryDequeue(out t))
61                 {
62                     Runing(t);
63                 }
64             }
65         }
66
67         /// <summary>
68         /// 设置运行方法为虚方法,方便子函数覆盖
69         /// </summary>
70         protected virtual void Runing(T run)
71         {
72             try
73             {
74                 //执行任务
75                 run.Run();
76                 //打印任务信息
77                 Console.WriteLine(DateTime.Now.ToString("HH:mm:ss:ffff") + " : " + Thread.CurrentThread.Name + " Action:" + run.ToString());
78             }
79             catch (Exception ex)
80             {
81                 //打印任务信息
82                 Console.WriteLine(DateTime.Now.ToString("HH:mm:ss:ffff") + " : " + Thread.CurrentThread.Name + " Action:" + run.ToString() + " Exception:" + ex);
83             }
84         }
85     }

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

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

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

任务实现类1

 1 /// <summary>
 2     /// 测试任务
 3     /// </summary>
 4     public class TestTask : BaseTask
 5     {
 6
 7         public override void Run()
 8         {
 9             Console.WriteLine("我只是用来测试的");
10         }
11     }

任务实现类2

 1 public class TestTask1 : BaseTask
 2     {
 3
 4         /// <summary>
 5         /// 执行任务
 6         /// </summary>
 7         public Action Test { get; set; }
 8
 9         public override void Run()
10         {
11             if (Test != null)
12             {
13                 Test();
14             }
15             Console.WriteLine("我只是用来测试的");
16         }
17     }

线程的实现类

 1     /// <summary>
 2     /// 测试线程
 3     /// </summary>
 4     public class TestThread : BaseThread<BaseTask>
 5     {
 6         public TestThread()
 7             : base("TestThread")
 8         {
 9
10         }
11     }

接下来我们看看测试效果

 1     class Program
 2     {
 3
 4         static void Main(string[] args)
 5         {
 6             TestThread tt = new TestThread();
 7             tt.AddTask(new TestTask() { TID = 1, TName = "测试1" });
 8             tt.AddTask(new TestTask1() { TID = 2, TName = "测试2" });
 9             tt.AddTask(new TestTask1() { TID = 2, TName = "测试3", Test = new Action(() => { Console.WriteLine("我要暂停3秒钟"); Thread.Sleep(3000); }) });
10             tt.AddTask(new TestTask() { TID = 3, TName = "测试4" });
11             Console.ReadLine();
12         }
13     }

运行结果图

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

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

时间: 2024-10-04 21:30:46

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

win32多线程 (二)线程同步之临界区 (critical sections)

所谓critical sections 意指一小块“用来处理一份被共享之资源”的程序代码.你可能必须在程序的许多地方处理这一块可共享的资源.所有这些程序代码可以被同一个critical  section 保护起来.为了阻止问题发生,一次只能有一个线程获准进入critical  section 中.critical section 并不是核心对象.使用方法: CRITICAL_SECTION g_section; 1:初始化 InitializeCriticalSection(&g_section

java多线程系列(二)

对象变量的并发访问 前言:本系列将从零开始讲解java多线程相关的技术,内容参考于<java多线程核心技术>与<java并发编程实战>等相关资料,希望站在巨人的肩膀上,再通过我的理解能让知识更加简单易懂. 目录 认识cpu.核心与线程 java多线程系列(一)之java多线程技能 java多线程系列(二)之对象变量的并发访问 java多线程系列(三)之等待通知机制 java多线程系列(四)之ReentrantLock的使用 线程安全 线程安全就是多线程访问时,采用了加锁机制,当一个

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

一.线程安全 多个线程在执行同一段代码的时候,每次的执行结果和单线程执行的结果都是一样的,不存在执行结果的二义性,就可以称作是线程安全的. 讲到线程安全问题,其实是指多线程环境下对共享资源的访问可能会引起此共享资源的不一致性.因此,为避免线程安全问题,应该避免多线程环境下对此共享资源的并发访问. 线程安全问题多是由全局变量和静态变量引起的,当多个线程对共享数据只执行读操作,不执行写操作时,一般是线程安全的:当多个线程都执行写操作时,需要考虑线程同步来解决线程安全问题. 二.线程同步(synchr

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

1.概念           因为java是完全面向对象的,所以在java中,我们说的线程,就是Thread类的一个实例对象.所以,一个线程就是一个对象,它有自己字段和方法. 2.创建线程 创建线程有2种方法:1.扩展线程父类Thread类 , 2.实现Runnable接口.2种方法是由区别的. 提示:Thread类已经实现了Runnable接口,Thread类中不但实现了run方法,也定义了更多的,全面的线程对象的操作方法,而Runnable接口中只有run这一个方法. 通过扩展Thread类

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

当我们使用 线程池的时候,可以使用 newCachedThreadPool()或者 newFixedThreadPool(int)等方法,其实我们深入到这些方法里面,就可以看到它们的是实现方式是这样的. 1 public static ExecutorService newCachedThreadPool() { 2 return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 3 60L, TimeUnit.SECONDS, 4 new Synchro

线程基础知识系列(二)线程的管理

本篇是线程基础知识系列的第二篇,主要简单江夏线程管理相关知识点. 线程基础知识系列(一)线程的创建和启动:说明了线程的2种创建和启动,join(),daemon线程,Callable 任务. 本文的主要内容 线程的状态 线程的优先级 sleep vs wait 线程的流程控制 Interrupt yield让出你的CPU 1.线程的状态 以<线程基础知识系列(一)线程的创建和启动>这张图,是程序的运行时线程信息截图.有main线程,user Threads,daemon Threads.现在咱

多线程基础二(线程的启动、终止,线程面临的三种问题)

一.线程的启动.终止方式 启动: start native(调用外部接口启动) 终止:    stop(类似kill,暴力终止)  interrupt 中断的方式 通过指令的方式 volatile boolean stop = false; public class InterruptDemo { private static int i; public static void main(String[] args) { Thread thread = new Thread(()->{ whil

多线程系列六:线程池

一. 线程池简介 1. 线程池的概念: 线程池就是首先创建一些线程,它们的集合称为线程池. 2. 使用线程池的好处 a) 降低资源的消耗.使用线程池不用频繁的创建线程和销毁线程 b) 提高响应速度,任务:T1创建线程时间,T2任务执行时间,T3线程销毁时间,线程池空闲的时候可以去执行T1和T2,从而提高响应 c) 提高线程的可管理性. 使用线程池可以很好地提高性能,线程池在系统启动时即创建大量空闲的线程,程序将一个任务传给线程池,线程池就会启动一条线程来执行这个任务,执行结束以后,该线程并不会死

带你玩转java多线程系列 二 Thread 和 Runnable

Thread 和 Runnable 1 Runnable是接口,而Thread是继承,可以同时实现多个接口,但是不能同时继承多个类 2 Runnable比Thread灵活的多 当我们使用Runnable测试多线程非常简单,因为Runnable是对Thread的进一步解耦 我们首先建立一个类记做为Model,实现Runnable接口,在类里建立一个实例变量,接着覆盖run方法. 我们重新建立一个含有main函数的类,在该类中我们首先建立一个Model类型的实例变量model,接着将该Runnabl