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 ...
随机推荐
- 测试URL有效性
方法一: #禁用滚动条 $ProgressPreference='silentlycontinue' Invoke-WebRequest "www.163.com" -UseBas ...
- JavaScript DOM对象和JQuery对象相互转换
1.分析源代码 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www ...
- C#小常识集锦(一)--《更锋利的CSharp代码》读书笔记
❀.采用类似匈牙利命名法为控件命令,对于其他变量申明则不需要了 e.g. Button btnAdd; e.g. TextBox txtUsername; e.g. ListBox lstFileNa ...
- DELPHI 多线程
效果不正确 unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Control ...
- auto_ptr解析
auto_ptr是当前C++标准库中提供的一种智能指针,或许相对于boost库提供的一系列眼花缭乱的智能指针, 或许相对于Loki中那个无所不包的智能指针,这个不怎么智能的智能指针难免会黯然失色.诚然 ...
- MySQL查询优化--细节理论
select的 high_priority还是比较有用,在实践中,平均5~6秒提高到3秒 ======================================================= ...
- 实例源码--Android自定义Gallery动画效果
相关文档与源码: 下载源码 技术要点: 1.自定义控件的使用 2.Gallery控件的使用实例 3.详细的源码注释 ...... 详细介绍: 1.自定义控件的使用 本套源码通过自定义控件的方式,继 ...
- 基于ActiveMQ的统一日志服务
概述 以ActiveMQ + Log4j + Spring的技术组合,实现基于消息队列的统一日志服务. 参考:Spring+Log4j+ActiveMQ实现远程记录日志——实战+分析 与参考文章的比较 ...
- Redis 有序集合(sorted set)
Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员. 不同的是每个元素都会关联一个double类型的分数.redis正是通过分数来为集合中的成员进行从小到大的排序. 有序 ...
- Integer的缓存和自动拆装箱
先看一个简单的例子: public class TestInteger { public static void main(String[] args) { System.out.println(&q ...