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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM