C# 线程--第四线程实例
概述
在前面几节中和大家分享了线程的一些基础使用方法,本章结合之前的分享来编写一些日常开发中应用实例,和编写多线程时一些注意点。如大家有好的实例也欢迎分享..
应用实例
应用:定时任务程序
场景:系统中常常会有一些需要定时去循环执行的存储过程或方法等,这时就出现了定时任务小程序。
模型:查询需定时执行的计划任务-->插入线程池-->执行任务
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# 线程--第四线程实例的更多相关文章
- Java多线程(四) 线程池
一个优秀的软件不会随意的创建.销毁线程,因为创建和销毁线程需要耗费大量的CPU时间以及需要和内存做出大量的交互.因此JDK5提出了使用线程池,让程序员把更多的精力放在业务逻辑上面,弱化对线程的开闭管理 ...
- 第四节:Task的启动的四种方式以及Task、TaskFactory的线程等待和线程延续的解决方案
一. 背景 揭秘: 在前面的章节介绍过,Task出现之前,微软的多线程处理方式有:Thread→ThreadPool→委托的异步调用,虽然也可以基本业务需要的多线程场景,但它们在多个线程的等待处理方面 ...
- {Python之线程} 一 背景知识 二 线程与进程的关系 三 线程的特点 四 线程的实际应用场景 五 内存中的线程 六 用户级线程和内核级线程(了解) 七 python与线程 八 Threading模块 九 锁 十 信号量 十一 事件Event 十二 条件Condition(了解) 十三 定时器
Python之线程 线程 本节目录 一 背景知识 二 线程与进程的关系 三 线程的特点 四 线程的实际应用场景 五 内存中的线程 六 用户级线程和内核级线程(了解) 七 python与线程 八 Thr ...
- Java多线程(四) —— 线程并发库之Atomic
一.从原子操作开始 从相对简单的Atomic入手(java.util.concurrent是基于Queue的并发包,而Queue,很多情况下使用到了Atomic操作,因此首先从这里开始). 很多情况下 ...
- C#中的线程(四)高级话题
C#中的线程(四)高级话题 Keywords:C# 线程Source:http://www.albahari.com/threading/Author: Joe AlbahariTranslato ...
- Java创建线程的四种方式
Java创建线程的四种方式 1.继承Thread类创建线程 定义Thread类的子类,并重写该类的run方法,run()方法的内容就是该线程执行的内容 创建Thread子类的实例,即创建了线程对象. ...
- java多线程(一)创建线程的四种方式
1. 什么是并发与并行 要想学习多线程,必须先理解什么是并发与并行 并行:指两个或多个事件在同一时刻发生(同时发生). 并发:指两个或多个事件在同一个时间段内发生. 2. 什么是进程.线程 进 ...
- Java并发编程 (四) 线程安全性
个人博客网:https://wushaopei.github.io/ (你想要这里多有) 一.线程安全性-原子性-atomic-1 1.线程安全性 定义: 当某个线程访问某个类时,不管运行时环境 ...
- java创建线程的四种方法
第一种: 通过继承Thread类创建线程 第二种: 通过实现Runnable接口创建线程 这两种早已烂记于心,这里就不作过多的介绍, 主要介绍其源码 Thread类 implements Runna ...
随机推荐
- SRV记录说明
SRV记录是DNS服务器的数据库中支持的一种资源记录的类型,它记录了哪台计算机提供了哪个服务这么一个简单的信息 SRV 记录:一般是为Microsoft的活动目录设置时的应用.DNS可以独立于活动 ...
- Oracle 生成随机密码
需求:需要定期更改密码.要求是1.密码位数11位.2.必须包含大小写字母.数字.特殊字符.3.排除一些特殊字符如().@.& oracle数据库中有可已生成随机密码包dbms_random,但 ...
- C++赋值运算符函数
为类添加赋值运算符函数: 类型定义 class CMyString { public: CMyString(char *pData = NULL); CMyString(const CMyString ...
- PHP中::、->、self、parent::、$this操作符的区别
在访问PHP类中的成员变量或方法时,如果被引用的变量或者方法被声明成const(定义常量)或者static(声明静态),那么就必须使用操作符::,反之如果被引用的变量或者方法没有被声明成const或者 ...
- MPEG简介 + 如何计算CBR 和VBR的MP3的播放时间
1. 声明本文所写内容,多数整理自互联网,版权归原作者所有笔者知识有限,文中难免有误,欢迎批评指正,admin (at) crifan.com觉得此文对你有帮助,想要发邮件来感谢的,也欢迎哈,^_^欢 ...
- 为Mono安装MySql连接驱动
为Mono安装MySql连接驱动(转) 2013 年 1 月 24 日.NETmono.MySql DOTNET and Mono by default only support database c ...
- jquery-ui autocomplete 自动完成功能
效果图
- AT-PagerAdapter
关于PagerAdapter的粗略翻译 英文版api地址:PagerAdapter(自备梯子) PagerAdapter 已知直接子类:FragmentPagerAdapter.Fra ...
- vs中两张图片的融合
这个其实就是从csdn上面下载的一个例程.感谢这位同学的总结,与源码的有偿分享. 本随笔就是把它通过4个随笔的拆分,实现的. 可以通过: http://blog.csdn.net/masibuaa/a ...
- JPA与ORM以及Hibernate