• Thread.Sleep引发ThreadAbortException异常


    短信平台记录日志模块,是通过异步方式来记录的,即日志工具类里初始化一个Queue对象,公共的写日志方法的处理逻辑是把日志消息放到Queue里。构造器里设定一个死循环,不停的读队,然后把日志消息持久化到磁盘的文本文件里。

    构造方法的代码如下:

    public Log()
    {
                //开启线程负责将日志写入到指定地点
                ThreadPool.QueueUserWorkItem(o =>
                {
                    try
                    {
                        while (true)
                        {
                            if (_messageQueue.Count > 0)
                            {
                                lock (_messageQueue)
                                {
                                    while (_messageQueue.Count > 0)
                                    {
                                        LogMessage logMessage = _messageQueue.Dequeue();
                                        WriteFile(logMessage);
                                    }
                                }
                            }
                            else
                            {
                                Thread.Sleep(300);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        LogMessage log = new LogMessage() { Content = "构造器执行报错:" + ex.ToString() };
                        FileHelper.WriteFile(string.Format(@"{0}{1:yyyy-MM-dd}-LOGERROR.txt", _logPath, DateTime.Now), log.GetFormattedLog());
                    }
                });
    }

    近期通过看线上站点日志,发现不定期会有ThreadAbortException被捕获,

    时间:2016-08-02 10:23:01
    构造器执行报错:System.Threading.ThreadAbortException: 正在中止线程。
       在 System.Threading.Thread.SleepInternal(Int32 millisecondsTimeout)
       在 Common.Log.<.ctor>b__1(Object o)
    -------------------------------------------------------------------------------
    时间:2016-08-02 10:47:32
    构造器执行报错:System.Threading.ThreadAbortException: 正在中止线程。
       在 System.Threading.Thread.SleepInternal(Int32 millisecondsTimeout)
       在 Common.Log.<.ctor>b__2(Object o)
    ----------------------------------------------------------------------------------------

    通过分析,当站点应用程序池回收或遇到其他未捕获的异常时,线程会被Abort,这时,当线程里的代码再被执行时,就会抛出ThreadAbortException异常。

    微软官方对ThreadAbortException的介绍:

    在调用 Abort 方法以销毁线程时,CLR将引发ThreadAbortExceptionThreadAbortException 是一种可捕获的特殊异常,但在 catch 块的结尾处它将自动被再次引发。引发此异常时,运行库将在结束线程前执行所有 finally 块。由于线程可以在 finally 块中执行未绑定计算,或调用 Thread.ResetAbort 来取消中止,所以不能保证线程将完全结束。如果您希望一直等到被中止的线程结束,可以调用 Thread.Join 方法。Join 是一个模块化调用,它直到线程实际停止执行时才返回。

    下面的示例说明如何中止线程。接收 ThreadAbortException 的线程使用 ResetAbort 方法取消中止请求并继续执行。

    using System;
    using System.Threading;
    using System.Security.Permissions;
    
    public class ThreadWork {
        public static void DoWork() {
            try {
                for(int i=0; i<100; i++) {
                    Console.WriteLine("Thread - working."); 
                    Thread.Sleep(100);
                }
            }
            catch(ThreadAbortException e) {
                Console.WriteLine("Thread - caught ThreadAbortException - resetting.");
                Console.WriteLine("Exception message: {0}", e.Message);
                Thread.ResetAbort();
            }
            Console.WriteLine("Thread - still alive and working."); 
            Thread.Sleep(1000);
            Console.WriteLine("Thread - finished working.");
        }
    }
    
    class ThreadAbortTest {
        public static void Main() {
            ThreadStart myThreadDelegate = new ThreadStart(ThreadWork.DoWork);
            Thread myThread = new Thread(myThreadDelegate);
            myThread.Start();
            Thread.Sleep(100);
            Console.WriteLine("Main - aborting my thread.");
            myThread.Abort();
            myThread.Join();
            Console.WriteLine("Main ending."); 
        }
    }

    运行结果:

    Thread - working.
    Main - aborting my thread.
    Thread - caught ThreadAbortException - resetting.
    Exception message: Thread was being aborted.
    Thread - still alive and working.
    Thread - finished working.
    Main ending.
    

    ————————————————————–我是萌萌哒分界线————————————————————

    生产者/消费者模式
    我们系统里的日志Helper类用到了Queue来实现异步记日志,提高系统容错和性能。现在想来,这就是一个生产者/消费者模式的运用。
    在分布式系统中,这个模式更适用,尤其是消息处理。 RabbitMQ正是基于这种需求而产生的消息中间件。
     
  • 相关阅读:
    C#中将dll汇入exe,并加壳
    很不错的在线格式转换网站
    Eclipse快捷键大全
    win7休眠的开启与关闭方法
    C#实现注册码
    Microsoft.CSharp.targets不存在解决方法
    数据库>SQL Server2005>第4季SQL从入门到提高>2SQL Server使用
    main函数名字写错,写成mian等等的错误提示
    CSS选择器
    斐波那契数的实现
  • 原文地址:https://www.cnblogs.com/buguge/p/5729515.html
Copyright © 2020-2023  润新知