首页 技术 正文
技术 2022年11月17日
0 收藏 630 点赞 5,060 浏览 3207 个字

Ø  前言

本文主要记录子线程导致 Topshelf 和 Quartz.NET 的 Windows 服务停止的现象,以及使用几种常用子线程的注意事项。因为我们有时可能需要开启多个线程执行复杂的逻辑,如果某个子线发生了异常就导致服务停止了,那还怎么愉快的玩耍?!

1.   还是以之前使用 Quartz.NET 实现作业串行执行为例,我们模拟在“发送短信”和“发送邮件”中发生异常的情况,代码如下:

1)   首先修改 SendSMSJob 作业

/// <summary>

/// 发送短信作业。

/// </summary>

public class SendSMSJob : IJob

{

/// <summary>

/// 作业被触发时执行该方法。

/// </summary>

public void Execute(IJobExecutionContext context)

{

Log.Logger.InfoFormat(“开始执行发送短信作业,线程Id为:{0}”, Thread.CurrentThread.ManagedThreadId);

int i = 10, j = 0;

int r = i / j;

Log.Logger.InfoFormat(“计算结果:{0} / {1} = {2}”, i, j, r);

Log.Logger.Info(“发送短信作业执行结束”);

}

}

2)   然后再修改 SendMailJob 作业

/// <summary>

/// 发送邮件作业。

/// </summary>

public class SendMailJob : IJob

{

/// <summary>

/// 异步方法。

/// </summary>

public async void AsyncMethod1()

{

await Task.Run(() =>

{

try

{

Log.Logger.InfoFormat(“开始执行(异步方法),线程为:{0}”, Thread.CurrentThread.ManagedThreadId); ;

string str = ((object)null).GetType().Name;

Log.Logger.InfoFormat(“结束执行(异步方法),结果:{0}”, str);

}

catch (Exception ex)

{

Log.Logger.ErrorFormat(“发送邮件作业发生异常:{0}”, ex.Message);

}

});

}

/// <summary>

/// 作业被触发时执行该方法。

/// </summary>

public void Execute(IJobExecutionContext context)

{

Log.Logger.InfoFormat(“开始执行发送邮件作业,线程Id为:{0}”, Thread.CurrentThread.ManagedThreadId);

//1. 使用委托异步调用的线程

Action action = new Action(() =>

{

try

{

Log.Logger.InfoFormat(“开始执行(委托异步),线程为:{0}”, Thread.CurrentThread.ManagedThreadId); ;

string str = ((object)null).GetType().Name;

Log.Logger.InfoFormat(“结束执行(委托异步),结果:{0}”, str);

}

catch (Exception ex)

{

Log.Logger.ErrorFormat(“发送邮件作业发生异常:{0}”, ex.Message);

}

});

action.BeginInvoke((asyncResult) =>

{

Action aciton = asyncResult.AsyncState as Action;

aciton.EndInvoke(asyncResult);

}, action);

//2. 使用开启的新线程

Thread thread = new Thread(() =>

{

try

{

Log.Logger.InfoFormat(“开始执行(开启新线程),线程为:{0}”, Thread.CurrentThread.ManagedThreadId); ;

string str = ((object)null).GetType().Name;

Log.Logger.InfoFormat(“结束执行(开启新线程),结果:{0}”, str);

}

catch (Exception ex)

{

Log.Logger.ErrorFormat(“发送邮件作业发生异常:{0}”, ex.Message);

}

});

thread.Start();

//3. 使用线程池中的线程

System.Threading.ThreadPool.QueueUserWorkItem((state) =>

{

try

{

Log.Logger.InfoFormat(“开始执行(线程池),线程为:{0}”, Thread.CurrentThread.ManagedThreadId); ;

string str = ((object)null).GetType().Name;

Log.Logger.InfoFormat(“结束执行(线程池),结果:{0}”, str);

}

catch (Exception ex)

{

Log.Logger.ErrorFormat(“发送邮件作业发生异常:{0}”, ex.Message);

}

});

//4. 使用异步方法中的线程(以 System.Threading.Tasks.Task.Run() 方式)

AsyncMethod1();

//5. 使用异步任务中的线程(以 System.Threading.Tasks.Task.Run() 方式)

System.Threading.Tasks.Task.Run(() =>

{

Log.Logger.InfoFormat(“开始执行(Task.Run()),线程为:{0}”, Thread.CurrentThread.ManagedThreadId); ;

string str = ((object)null).GetType().Name;

Log.Logger.InfoFormat(“结束执行(Task.Run()),结果:{0}”, str);

});

//6. 使用异步任务中的线程(以 System.Threading.Tasks.Task.Factory.StartNew() 方式)

System.Threading.Tasks.Task.Factory.StartNew(() =>

{

Log.Logger.InfoFormat(“开始执行(Task.Factory.StartNew()),线程为:{0}”, Thread.CurrentThread.ManagedThreadId); ;

string str = ((object)null).GetType().Name;

Log.Logger.InfoFormat(“结束执行(Task.Factory.StartNew()),结果:{0}”, str);

}).Start();

Log.Logger.Info(“发送邮件作业执行结束”);

}

}

2.   分别运行 SendMailJob 作业的几种方式(运行时注释其他 5 种方式)

1)   没有加 try/catch 的情况

2)   加了 try/catch 的情况

3)   分析与总结

1.   首先主线程(就是 windows 服务主动开启的线程)发生异常时,终止当前线程执行,但不会停止服务。

2.   【推荐】异步任务(Task)开启的线程发生异常时,也是终止当前线程执行,但不会停止服务。

3.   使用(未加 try/catch 时)委托异步调用的线程、开启的新线程、线程池中的线程、异步方法中的线程,发生异常时,会停止服务!

4.   使用(加 try/catch 时)开启的新线程、线程池中的线程、异步方法中的线程,发生异常时,不会停止服务。

5.   使用(加 try/catch 时)委托异步调用的线程同样会停止服务!

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,083
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,558
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,407
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,180
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,816
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,899