在写windows服务的时候需要用到多线程跑数据,执行方法中用lock锁住一段代码,记录日志后发现无效,没起作用。
program 代码如下:
/// <summary> /// 应用程序的主入口点 /// </summary> static void Main() { Log4Helper.GetInstance().Info("服务启动"); try { ThreadPool.QueueUserWorkItem(PushCache, new SearchParam() { MsgType = 3 }); ThreadPool.QueueUserWorkItem(PushCache, new SearchParam() { MsgType = 3 }); ThreadPool.QueueUserWorkItem(PushCache, new SearchParam() { MsgType = 3 }); ThreadPool.QueueUserWorkItem(PushCache, new SearchParam() { MsgType = 3 }); ThreadPool.QueueUserWorkItem(PushCache, new SearchParam() { MsgType = 3 }); TimeSpan sleepTime = new TimeSpan(1, 0, 0); //休眠一小时 while (true) { Thread.Sleep(sleepTime); } } catch (Exception e) { Log4Helper.GetInstance().Error(e); } } public static void PushCache(object obj) { var search = obj as SearchParam; MessageCacheBll.GetInstance().PushCache(search); }
public class SearchParam
{
/// <summary>
/// 消息类型
/// </summary>
public int MsgType { get; set; }
}
MessageCacheBll类方法如下:
public class MessageCacheBll { private readonly object _lockThread = new object(); #region Instance private static MessageCacheBll _instance; public static MessageCacheBll GetInstance() { return _instance ?? (_instance = new MessageCacheBll()); } #endregion /// <summary> /// 按照消息类型和学段跑数据 /// </summary> /// <param name="search">msgType消息类型</param> public void PushCache(object obj) { var search = (obj as SearchParam) ?? new SearchParam(); try { var sqlWhere = ""; if (search.MsgType == -1) { sqlWhere += " and spm.type in(1,3,4,5,6,100) ";//1系统消息、3消息、4作业、5成绩通知、6请假、100成绩通知的发件箱用 } else { sqlWhere += string.Format(" and spm.type={0} ", search.MsgType); } List<SpMessageDto> list = new List<SpMessageDto>(); var updateCacheStatusResult = false;//更新缓存状态结果 //锁 获取当前线程要跑的数据 try { lock (_lockThread) { Log4Helper.GetInstance().Info(string.Format("--------lock-开始 threadid{0}--------", Thread.CurrentThread.ManagedThreadId)); list = MessageCacheDal.GetInstance().GetNoCacheMessageList(sqlWhere); if (list != null && list.Count > 0) { var idList = list.Select(t => t.Id).ToList(); updateCacheStatusResult = MessageCacheDal.GetInstance() .UpdateMessageCacheStatus((int)AppEnum.CacheStatus.Caching, idList); } Log4Helper.GetInstance().Info(string.Format("--------lock-结束 threadid{0}--------", Thread.CurrentThread.ManagedThreadId)); } } catch (Exception e) { Log4Helper.GetInstance().Error(e); } } catch (Exception e) { Log4Helper.GetInstance().Error(string.Format("异常 msgType:{0}。", search.MsgType), e); } } } }
日志输出结果:
2020-01-01 11:36:02,872 服务启动
2020-01-01 11:36:02,882 --------lock-开始 threadid4--------
2020-01-01 11:36:02,884 --------lock-开始 threadid5--------
2020-01-01 11:36:02,884 --------lock-开始 threadid7--------
2020-01-01 11:36:02,884 --------lock-开始 threadid3--------
2020-01-01 11:36:03,325 --------lock-结束 threadid3--------
2020-01-01 11:36:03,363 --------lock-结束 threadid7--------
2020-01-01 11:36:03,367 --------lock-结束 threadid4--------
2020-01-01 11:36:03,368 --------lock-开始 threadid6--------
2020-01-01 11:36:03,370 --------lock-结束 threadid5--------
2020-01-01 11:36:03,595 --------lock-结束 threadid6--------
解决方案:
方法一:去掉program中的PushCache方法,main方法中直接调用MessageCacheBll.GetInstance().PushCache(search)
示例代码:
/// <summary> /// 应用程序的主入口点 /// </summary> static void Main() { Log4Helper.GetInstance().Info("服务启动"); try { ThreadPool.QueueUserWorkItem(MessageCacheBll.GetInstance().PushCache, new SearchParam() { MsgType = 3 }); ThreadPool.QueueUserWorkItem(MessageCacheBll.GetInstance().PushCache, new SearchParam() { MsgType = 3 }); ThreadPool.QueueUserWorkItem(MessageCacheBll.GetInstance().PushCache, new SearchParam() { MsgType = 3 }); ThreadPool.QueueUserWorkItem(MessageCacheBll.GetInstance().PushCache, new SearchParam() { MsgType = 3 }); ThreadPool.QueueUserWorkItem(MessageCacheBll.GetInstance().PushCache, new SearchParam() { MsgType = 3 }); TimeSpan sleepTime = new TimeSpan(1, 0, 0); //休眠一小时 while (true) { Thread.Sleep(sleepTime); } } catch (Exception e) { Log4Helper.GetInstance().Error(e); } }
日志输出结果:
2020-01-01 11:52:47,016 服务启动
2020-01-01 11:52:47,027 --------lock-开始 threadid3--------
2020-01-01 11:52:47,508 --------lock-结束 threadid3--------
2020-01-01 11:52:47,508 --------lock-开始 threadid4--------
2020-01-01 11:52:47,852 --------lock-结束 threadid4--------
2020-01-01 11:52:47,852 --------lock-开始 threadid5--------
2020-01-01 11:52:48,038 --------lock-结束 threadid5--------
2020-01-01 11:52:48,038 --------lock-开始 threadid6--------
2020-01-01 11:52:48,292 --------lock-结束 threadid6--------
2020-01-01 11:52:48,292 --------lock-开始 threadid7--------
2020-01-01 11:52:48,413 --------lock-结束 threadid7--------
方法二:将MessageCacheBll中的PushCache放到program中,lock也放到program中
示例代码:
static class Program { /// <summary> /// 应用程序的主入口点 /// </summary> static void Main() { Log4Helper.GetInstance().Info("服务启动"); try { ThreadPool.QueueUserWorkItem(PushCache, new SearchParam() { MsgType = 3 }); ThreadPool.QueueUserWorkItem(PushCache, new SearchParam() { MsgType = 3 }); ThreadPool.QueueUserWorkItem(PushCache, new SearchParam() { MsgType = 3 }); ThreadPool.QueueUserWorkItem(PushCache, new SearchParam() { MsgType = 3 }); ThreadPool.QueueUserWorkItem(PushCache, new SearchParam() { MsgType = 3 }); TimeSpan sleepTime = new TimeSpan(1, 0, 0); //休眠一小时 while (true) { Thread.Sleep(sleepTime); } } catch (Exception e) { Log4Helper.GetInstance().Error(e); } } private static readonly object _lockThread = new object(); /// <summary> /// 按照消息类型和学段跑数据 /// </summary> /// <param name="search">msgType消息类型</param> public static void PushCache(object obj) { var search = (obj as SearchParam) ?? new SearchParam(); try { var sqlWhere = ""; if (search.MsgType == -1) { sqlWhere += " and spm.type in(1,3,4,5,6,100) "; } else { sqlWhere += string.Format(" and spm.type={0} ", search.MsgType); } List<SpMessageDto> list = new List<SpMessageDto>(); var updateCacheStatusResult = false;//更新缓存状态结果 //锁 获取当前线程要跑的数据 try { lock (_lockThread) { Log4Helper.GetInstance().Info(string.Format("--------lock-开始 threadid{0}--------", Thread.CurrentThread.ManagedThreadId)); list = MessageCacheDal.GetInstance().GetNoCacheMessageList(sqlWhere); if (list != null && list.Count > 0) { var idList = list.Select(t => t.Id).ToList(); updateCacheStatusResult = MessageCacheDal.GetInstance() .UpdateMessageCacheStatus((int)AppEnum.CacheStatus.Caching, idList); } Log4Helper.GetInstance().Info(string.Format("--------lock-结束 threadid{0}--------", Thread.CurrentThread.ManagedThreadId)); } } catch (Exception e) { Log4Helper.GetInstance().Error(e); } } catch (Exception e) { Log4Helper.GetInstance().Error(string.Format("异常 msgType:{0}。", search.MsgType), e); } }
日志输出记录:
2020-01-01 11:57:35,878 服务启动
2020-01-01 11:57:35,888 --------lock-开始 threadid4--------
2020-01-01 11:57:36,586 --------lock-结束 threadid4--------
2020-01-01 11:57:36,586 --------lock-开始 threadid6--------
2020-01-01 11:57:36,789 --------lock-结束 threadid6--------
2020-01-01 11:57:36,789 --------lock-开始 threadid3--------
2020-01-01 11:57:37,186 --------lock-结束 threadid3--------
2020-01-01 11:57:37,186 --------lock-开始 threadid5--------
2020-01-01 11:57:37,279 --------lock-结束 threadid5--------
2020-01-01 11:57:37,279 --------lock-开始 threadid7--------
2020-01-01 11:57:37,394 --------lock-结束 threadid7--------