概述

在前面几节中和大家分享了线程的一些基础使用方法,本章结合之前的分享来编写一些日常开发中应用实例,和编写多线程时一些注意点。如大家有好的实例也欢迎分享..

应用实例

应用:定时任务程序

场景:系统中常常会有一些需要定时去循环执行的存储过程或方法等,这时就出现了定时任务小程序。

模型:查询需定时执行的计划任务-->插入线程池-->执行任务

static void MainMethod()
{
Thread thead; thead = new Thread(QueryTask);
thead.IsBackground = true;
thead.Start(); Console.Read();
} /// <summary>
/// 查询计划任务
/// </summary>
static void QueryTask()
{
TaskModel todo_taskModel;
while (true)
{
int count = new Random().Next(, ); //模拟产生任务记录数
for (int i = ; i < count; i++)
{
todo_taskModel = new TaskModel() { TaskID = i, ITime = DateTime.Now };
ThreadPool.QueueUserWorkItem(InvokeThreadMethod, todo_taskModel);
} Thread.Sleep(); //30s循环一次
}
} /// <summary>
/// 完成计划任务
/// </summary>
/// <param name="taskModel"></param>
static void InvokeThreadMethod(object taskModel)
{
TaskModel model = (TaskModel)taskModel; Console.WriteLine("执行任务ID:{0}......执行完成.{1}", model.TaskID, model.ITime);
} /// <summary>
/// 任务实体
/// </summary>
class TaskModel
{
public int TaskID { get; set; }
public DateTime ITime { get; set; }
}

1.查询计划任务时只管有任务就推给线程池,不等待线程池中任务是否完成.(避免有些计划任务耗时比较长,阻塞后面定时任务执行时间)每隔30秒循环一次计划任务.

2.每条计划任务完成后打印相应信息.(也可记录日志)

3.如果查询计划任务记录数较多,可调整相应的循环时间间隔。避免任务插入线程池时间过长阻塞后面定时任务执行时间。

应用:数据推送程序

场景:在我们日常系统中会存在很多接口数据需要实时推送给第三方平台(如:会员信息发生变化推送给微信平台..)。这时我们就需写一些数据推送程序。

模型:检索任务-->插入线程池-->等待线程池任务完成-->提示任务完成

static void MainMethodB()
{
Thread thread = new Thread(QueryTaskB);
thread.IsBackground = true;
thread.Start(); Console.Read();
} static void QueryTaskB()
{
MutipleThreadResetEvent countdown;
TaskModeB model;
while (true)
{
int RandomNumber = new Random().Next(, );
countdown = new MutipleThreadResetEvent(RandomNumber);
for (int i = ; i < RandomNumber; i++)
{
model = new TaskModeB() { TaskId = i, ITime = DateTime.Now, manualResetEvent = countdown };
ThreadPool.QueueUserWorkItem(InvokeThreadMethodB, model);
} //等待所有线程执行完毕
countdown.WaitAll();
Console.WriteLine("线程池任务已完成.完成时间:{0}", DateTime.Now);
Thread.Sleep();
}
} static void InvokeThreadMethodB(object obj)
{
TaskModeB model = (TaskModeB)obj;
Thread.Sleep();
Console.WriteLine("执行任务ID:{0},执行时间:{1},完成时间:{2}", model.TaskId, model.ITime, DateTime.Now); //发送信号量 本线程执行完毕
model.manualResetEvent.SetOne();
} class TaskModeB
{
public int TaskId { set; get; }
public DateTime ITime { set; get; }
public MutipleThreadResetEvent manualResetEvent { set; get; }
} /// <summary>
/// 解决问题:WaitHandle.WaitAll(evetlist)方法最大只能等待64个ManualResetEvent事件
/// </summary>
public class MutipleThreadResetEvent
{
private readonly ManualResetEvent done;
private readonly int total;
private long current; /// <summary>
/// 构造函数
/// </summary>
/// <param name="total">需要等待执行的线程总数</param>
public MutipleThreadResetEvent(int total)
{
this.total = total;
current = total;
done = new ManualResetEvent(false);
} /// <summary>
/// 唤醒一个等待的线程
/// </summary>
public void SetOne()
{
// Interlocked 原子操作类 ,此处将计数器减1
if (Interlocked.Decrement(ref current) == )
{
//当所以等待线程执行完毕时,唤醒等待的线程
done.Set();
}
} /// <summary>
/// 等待所以线程执行完毕
/// </summary>
public void WaitAll()
{
done.WaitOne();
} /// <summary>
/// 释放对象占用的空间
/// </summary>
public void Dispose()
{
((IDisposable)done).Dispose();
}
}

QueryTaskB()在检索任务记录数后会记录任务条数,并实例化对应的ManualResetEvent数组,做为参数传给线程池中线程任务。

最后等待线程池中所有任务执行完成。后续可根据实际需要编写各自业务逻辑。

两个实例的不同点:是否等待线程池中的所有任务完成。

实例1中定时任务对执行的时间要求比较高,到了某个时间点必须执行某个任务。所以不能等待线程池中的任务完成。

缺点:有任务就插入线程池,有些任务可能会执行很久,线程池每隔30秒循环一次,最后会导致线程池中有存在很多耗时很长的任务在线程池中未执行完。当线程池中线程数达到1023(线程池默认最大线程数)后线程池就不会在创建新的线程数去完成新的任务,只能等待当前线程池中线程数得到释放。

实例2中数据推送程序对推送的时间要求相对1中要低一点。接口表中只要检索到数据就推送给第三方平台。一般每次传输数据量不是很多,但很频繁。

缺点:当推送数据量大时,执行任务时间可能会较长。主线程会等待线程池中的所有任务完成。所有每次循环检索任务的时间间隔可能会出现30S+NS现象。

C# 线程--第四线程实例的更多相关文章

  1. Java多线程(四) 线程池

    一个优秀的软件不会随意的创建.销毁线程,因为创建和销毁线程需要耗费大量的CPU时间以及需要和内存做出大量的交互.因此JDK5提出了使用线程池,让程序员把更多的精力放在业务逻辑上面,弱化对线程的开闭管理 ...

  2. 第四节:Task的启动的四种方式以及Task、TaskFactory的线程等待和线程延续的解决方案

    一. 背景 揭秘: 在前面的章节介绍过,Task出现之前,微软的多线程处理方式有:Thread→ThreadPool→委托的异步调用,虽然也可以基本业务需要的多线程场景,但它们在多个线程的等待处理方面 ...

  3. {Python之线程} 一 背景知识 二 线程与进程的关系 三 线程的特点 四 线程的实际应用场景 五 内存中的线程 六 用户级线程和内核级线程(了解) 七 python与线程 八 Threading模块 九 锁 十 信号量 十一 事件Event 十二 条件Condition(了解) 十三 定时器

    Python之线程 线程 本节目录 一 背景知识 二 线程与进程的关系 三 线程的特点 四 线程的实际应用场景 五 内存中的线程 六 用户级线程和内核级线程(了解) 七 python与线程 八 Thr ...

  4. Java多线程(四) —— 线程并发库之Atomic

    一.从原子操作开始 从相对简单的Atomic入手(java.util.concurrent是基于Queue的并发包,而Queue,很多情况下使用到了Atomic操作,因此首先从这里开始). 很多情况下 ...

  5. C#中的线程(四)高级话题

    C#中的线程(四)高级话题   Keywords:C# 线程Source:http://www.albahari.com/threading/Author: Joe AlbahariTranslato ...

  6. Java创建线程的四种方式

    Java创建线程的四种方式 1.继承Thread类创建线程 定义Thread类的子类,并重写该类的run方法,run()方法的内容就是该线程执行的内容 创建Thread子类的实例,即创建了线程对象. ...

  7. java多线程(一)创建线程的四种方式

    1.   什么是并发与并行 要想学习多线程,必须先理解什么是并发与并行 并行:指两个或多个事件在同一时刻发生(同时发生). 并发:指两个或多个事件在同一个时间段内发生. 2.   什么是进程.线程 进 ...

  8. Java并发编程 (四) 线程安全性

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 一.线程安全性-原子性-atomic-1 1.线程安全性 定义: 当某个线程访问某个类时,不管运行时环境 ...

  9. java创建线程的四种方法

    第一种:  通过继承Thread类创建线程 第二种: 通过实现Runnable接口创建线程 这两种早已烂记于心,这里就不作过多的介绍, 主要介绍其源码 Thread类 implements Runna ...

随机推荐

  1. hdu 5587 Array 数学题

    Array Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5587 De ...

  2. delphi 01设置 字体属性

    设置/获取 字体属性 名称 大小 粗体 斜体 下划线 删除线 颜色1 颜色2   uses MSHTML;   //设置 //------------------------------------- ...

  3. delphi treeview 鼠标移动显示hint信息

    procedure TForm1.TreeView1MouseMove(Sender: TObject; Shift: TShiftState;   X, Y: Integer); var   Nod ...

  4. Android-L-Samples

    https://github.com/s3xy4ngyc/Android-L-Samples

  5. android service总结

    1.通过startservice方法启动一个服务.service不能自己启动自己.若在一个服务中启动一个activity则,必须是申明一个全新的activity任务TASK.通过startservic ...

  6. android151 笔记 3

    34. 对android虚拟机的理解,包括内存管理机制垃圾回收机制. 虚拟机很小,空间很小,谈谈移动设备的虚拟机的大小限制 16M , 谈谈加载图片的时候怎么处理大图片的,压缩. 垃圾回收,没有引用的 ...

  7. System.Data.SQLite.EF6

    2015.1.21 到目前为止这个破玩意不支持code first 建数据库 建表 代替方案   SQL Server Compact -------------------------------- ...

  8. session超时和cookie过期

    一.Cookie的过期和Session的超时有什么区别? 会话的超时由服务器来维护,它不同于Cookie的失效日期.首先,会话一般基于驻留内存的cookie不是持续性的cookie,因而也就没有截至日 ...

  9. [转]网站优化-IIS7下静态文件的优化

    本文转自:http://www.cnblogs.com/Leung/archive/2009/10/26/1590256.html 在网站开发过程中,通常我们会对网站的静态文件做处事,像图片文件,CS ...

  10. Leetcode 190. Reverse Bits(反转比特数)

    Reverse bits of a given 32 bits unsigned integer. For example, given input 43261596 (represented in ...