C#中定时任务被阻塞问题的解决方法
作者:JerryMouseLi 发布时间:2023-10-27 00:56:02
目录
1.摘要
2.C#中定时任务的最简方法
3.定时任务阻塞现象
4.阻塞现象原因分析
5.问题解决
总结
1.摘要
本文会介绍一个C#中最简单定时任务的使用方法,以及会遇到的定时任务被阻塞现象,从笔者理解的角度分析原因。以及提供解决方案。
2.C#中定时任务的最简方法
protected internal void PollClient()
{
int i=0;
Timer t = new Timer(p => {
i++;
if (deviceContextList.Count > 0)
{
var deviceContext=GetDeviceContext("123456789");
SendMessage(messageList[i%7],deviceContext.tcpSession.writerContext);
logger.Info("客户端数量:"+ deviceContextList.Count);
}
else
{
logger.Info("客户端数量为0");
Console.WriteLine("客户端数量为0");
}
}, null, 0, 1000) ;
}
上面的timer方法提供于微软System.Threading命名空间。System.Threading.Timer 是由线程池调用的。所有的Timer对象只使用了一个线程来管理。这个线程知道下一个回调对象在什么时候到期。下一个回调对象到期时,线程就会唤醒,在内部调用ThreadPool 的 QueueUserWorkItem,将一个工作项添加到线程池队列中,使你的回调方法得到调用。此方法有多个重载,具体读者可以自行去看。
Timer(TimerCallback callback, object state, int dueTime, int period)
第一个参数callback是回调方法,第二个参数state可以传参给回调方法的参数,第三个参数dueTime是第一次执行回调函数的延时时间,单位毫秒,第四个参数period是调用回调函数的时间间隔。使用起来是不是特别方便,把你需要执行的定时任务放在回调方法中,可独立写成方法,也可像上面一样写成匿名方法的形式。
3.定时任务阻塞现象
当上述任务被执行了几千次以后,定时任务会阻塞,不再执行,也不再打印日志。并且上面的写法有缺陷,。如果回调方法的执行时间很长,计时器可能(在上个回调还没有完成的时候)再次触发。这可能造成多个线程池线程同时执行你的回调方法。并且线程切换也会造成诸多损耗时间。
4.阻塞现象原因分析
上面的方法中使用局部变量来创建指向一个线程定时器。因为局部变量会被GC回收,导致定时器失效。
具体改进如下:
static int i=0;
static Timer _timer = null;
protected void PollClient()
{
_timer = new Timer(TimerCallback, null, 1000, Timeout.Infinite) ;
}
private void TimerCallback(object state)
{
try
{
i++;
if (deviceContextList.Count > 0)
{
var deviceContext = GetDeviceContext("123456789");
SendMessage(messageList[i % 7], deviceContext.tcpSession.writerContext);
logger.Info("客户端数量:" + deviceContextList.Count + "循环次数:" + i);
}
else
{
logger.Info("客户端数量为0" + "循环次数:" + i);
Console.WriteLine("客户端数量为0" + "循环次数:" + i);
}
}
catch (Exception e)
{
logger.Error("定时测试下发报文异常:" + e);
}
finally
{
_timer.Change( 1000, Timeout.Infinite);
}
}
将定时器与计数变量设置为static是为了定时器不被GC回收。定时任务执行完成之后再设置下次调用时间间隔是为了该任务不过多占用线程池中的线程,节省线程切换时间等。
5.问题解决
可以看到任务已经被执行了86665次,优化后不再被GC回收。
来源:https://www.cnblogs.com/JerryMouseLi/p/15543495.html
猜你喜欢
- 其实早在.NET 4.5的时候M$就在.NET中引入了async和await关键字(VB为Async和Await)来简化异步调用的编程模式。
- 前言之前写过一篇关于配置中心对配置内容加密解密的介绍:《Spring Cloud构建微服务架构:分布式配置中心(加密解密) 》。在这篇文章中
- 本文实例为大家分享了Unity实现切割图集工具的具体代码,供大家参考,具体内容如下操作步骤先将脚本拖入Editor1.选中要切割的图片,te
- 用java来打包文件生成压缩文件,有两个地方会出现乱码:内容的中文乱码问题:修改sun的源码。使用开源的类库org.apache.tools
- 本文实例为大家分享了Java实现猜拳游戏的具体代码,供大家参考,具体内容如下一、问题简介通过控制台方式实现一个人机对战的猜拳游戏,用户通过输
- 目录前言一、内存优化策略二、具体优化的点1.避免内存泄漏2.Bitmap等大对象的优化策略(1) 优化Bitmap分辨率(2) 优化单个像素
- 本文实例讲述了Android简单获取经纬度的方法。分享给大家供大家参考,具体如下:public void getLoc() {
- 本文介绍了eclipse下搭建hibernate5.0环境的步骤,分享给大家,具体如下:hibernate引入的jar包:hibernate
- IFormattable接口提供了ToString()方法的定义,使用该方法可以将对象的值按照指定的格式转化成字符串的功能。下面是ToStr
- 之前的工作中,需要实现一个功能就是GridView中的item可以自由拖动, 思考了一下,其实实现起来不是很困难,主要工作就是交换节点,以及
- 比较简单的一个控件,就是加些逻辑处理而已,以前貌似是直接监听的,封装起来方便点public class AccountTxtView ext
- 大致思路:注解实现方式:就是用 反射机制. 获取指定的包下使用了注解的类,存储在一个map容器, 然后获取map容器下类的属性, 利用反射给
- 使用Java生成图片验证码完全解析在 Java 中开发图片验证码功能,您可以使用 Java 图形处理库,比如 Java Advanced I
- 本文实例讲述了Android开发实现跟随手指的小球效果。分享给大家供大家参考,具体如下:配置DrawView类用于绘制小球public cl
- 一般文本文件我们以日志文件.log文件为例:import java.io.BufferedReader; import java.io.Fi
- java swing GUI窗口美化一般我们写出的窗口是这个样子的,文本框和按钮都不是太美观,如果按钮是原色的就更难看了。今天发现了一个更加
- @RequestBody出现400 Bad Request的问题今天与同事调试一个接口,发现后台使用@RequestBody老是获取不到数据
- 1. MyBatis 中 #{}和 ${}的区别是什么?#{}是预编译处理,${}是字符替换。 在使用 #{}时,MyBatis 会将 SQ
- java在jdk1.5中引入了注解,spring框架也正好把java注解发挥得淋漓尽致。下面会讲解Spring中自定义注解的简单流程,其中会
- 建立Android项目,如果会的话特别简单,不会的话让自己去琢磨也需要一定的时间!小编之后将自己学习Android的经验给大家分享出来!1、