异步多线程的异常,抓不到,因为是在子线程执行。

#region 多线程的异常处理、线程取消、临时变量、lock
            {
                try
                {
                    List<Task> list = new List<Task>();
                    TaskFactory taskFactory = new TaskFactory();
                    //取消线程
                    CancellationTokenSource cts = new CancellationTokenSource();
                    for (int i = 0; i < 5; i++)
                    {
                        string name = "task" + i;
                        //无参数,无返回值的一个委托
                        Action act = new Action(() =>
                        {
                            try
                            {
                                if (name == "task4")
                                {
                                    throw new Exception("抛出异常信息");
                                }
                                Thread.Sleep(2000);
                                //检查Task是否被取消了
                                if (cts.IsCancellationRequested)
                                {
                                    Console.WriteLine(name + " 被取消:" + cts.IsCancellationRequested);
                                }
                                else
                                {
                                    Console.WriteLine(name + " 执行成功");
                                }
                            }
                            catch (Exception ex)
                            {
                                cts.Cancel();//取消,所有子线程都会被取消
                                Console.WriteLine("子线程异常:{0}", ex.Message);
                            }
                        });

                        Task task = taskFactory.StartNew(act, cts.Token);
                        list.Add(task);
                        //cts.Token是一个标识,用来标记线程是否已经被取消了
                        //输出结果
                        //子线程异常:抛出异常信息
                        //task2 被取消:True
                        //task1 被取消:True
                        //task3 被取消:True
                        //task0 被取消:True
                    }
                    Task.WaitAll(list.ToArray());
                }
                catch (AggregateException ex)
                {
                    foreach (var item in ex.InnerExceptions)
                    {
                        Console.WriteLine(item.Message);
                    }
                }

            }
            #endregion

            #region 多线程延迟问题
            {
                Action<int> act = new Action<int>(t =>
                {
                    Thread.Sleep(200);
                    Console.WriteLine(t);
                });
                for (int i = 0; i < 10; i++)
                {
                    //Task.Run 需要接受 无参数、无返回值 的Action,所以需要包装一下
                    //会出现错误,输出的全部是 10,因为Task.Run去申请线程后并没有立即执行,当执行的时候for循环已经结束,i已经变成10了
                    //Task.Run(() => act(i));

                    //解决方法,每次循环都会创建一个新的变量k,执行的时候引用的是当时的k
                    int k = i;
                    Task.Run(() => act(k));
                }
            }
            #endregion

 线程变量副本ThreadLocal/ThreadStatic

static ThreadLocal<string> threadLocal = new ThreadLocal<string>();
static void Main(string[] args)
{
    List<Task> list = new List<Task>();
    for (int i = 0; i < 4; i++)
    {
        Task task = Task.Run(() =>{
             Thread.Sleep(2000);
             threadLocal.Value = "线程" + Thread.CurrentThread.ManagedThreadId;
             PrintLocalData();
         });
         list.Add(task);
     }
     Task.WaitAll(list.ToArray());
}
public static void PrintLocalData()
{
    Console.WriteLine("{0}:{1}", Thread.CurrentThread.ManagedThreadId, threadLocal.Value);
}

结果:5:线程5
8:线程8
9:线程9
11:线程11
ThreadLocal的源码中很简单,就是使用了ThreadStatic特性:[ThreadStatic]使每个线程都有一个变量副本。
所以,上面的static ThreadLocal<string> threadLocal = new ThreadLocal<string>(); 可以替换为:
[ThreadStatic]
static string localValue;
注:[ThreadStatic]依赖当前线程,当线程池的线程被重用时,可能该字段又表现为“公用”的了。及时清空可以一定程度上解决该问题。
posted on 2017-11-15 17:38  邢帅杰  阅读(293)  评论(0编辑  收藏  举报