• c#多线程lock无效


     在写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--------

  • 相关阅读:
    bzoj 2216 Lightning Conductor
    一些有趣的问题合集
    Codeforces 40E Number Table
    Codeforces 37D Lesson Timetable
    bzoj 4289 Tax
    bzoj 2844 albus就是要第一个出场
    bzoj 2115 Xor
    luogu 3790 文艺数学题
    bzoj 1420 Discrete Root
    Lucas定理学习笔记
  • 原文地址:https://www.cnblogs.com/jiangqw/p/12128497.html
Copyright © 2020-2023  润新知