zoukankan      html  css  js  c++  java
  • 线程异常处理和取消和线程锁

     /// 1 多异常处理和线程取消
        /// 2 多线程的临时变量
        /// 3 线程安全和锁lock
        class Program
        {
    
            static void Main(string[] args)
            {
                #region 多线程异常处理
                //{
                //    try
                //    {
                //        List<Task> taskList = new List<Task>();
                //        for (int i = 0; i < 100; i++)
                //        {
                //            string name = $"btnThreadCore_Click_{i}";
                //            taskList.Add(Task.Run(() =>
                //            {
                //                if (name.Equals("btnThreadCore_Click_11"))
                //                {
                //                    throw new Exception("btnThreadCore_Click_11异常");
                //                }
                //                else if (name.Equals("btnThreadCore_Click_12"))
                //                {
                //                    throw new Exception("btnThreadCore_Click_12异常");
                //                }
                //                else if (name.Equals("btnThreadCore_Click_38"))
                //                {
                //                    throw new Exception("btnThreadCore_Click_38异常");
                //                }
                //                Console.WriteLine($"This is {name}成功 ThreadId={Thread.CurrentThread.ManagedThreadId.ToString("00")}");
                //            }));
                //        }
                //        //多线程里面抛出的异常,会终结当前线程;但是不会影响别的线程;
                //        //那线程异常哪里去了? 被吞了,
                //        //假如我想获取异常信息,还需要通知别的线程
                //        Task.WaitAll(taskList.ToArray());//1 可以捕获到线程的异常
                //    }
                //    catch (AggregateException aex)//2 需要try-catch-AggregateException
                //    {
                //        foreach (var exception in aex.InnerExceptions)
                //        {
                //            Console.WriteLine(exception.Message);
                //        }
                //    }
                //    catch (Exception ex)//可以多catch  先具体再全部
                //    {
                //        Console.WriteLine(ex);
                //    }
                //    //线程异常后经常是需要通知别的线程,而不是等到WaitAll,问题就是要线程取消
                //    //工作中常规建议:多线程的委托里面不允许异常,包一层try-catch,然后记录下来异常信息,完成需要的操作
                //}
    
                #endregion
    
                #region 线程取消
                //{
                //    //多线程并发任务,某个失败后,希望通知别的线程,都停下来,how?
                //    //Thread.Abort--终止线程;向当前线程抛一个异常然后终结任务;线程属于OS资源,可能不会立即停下来
                //    //Task不能外部终止任务,只能自己终止自己
    
                //    //cts有个bool属性IsCancellationRequested 初始化是false
                //    //调用Cancel方法后变成true(不能再变回去),可以重复cancel
                //    try
                //    {
                //        CancellationTokenSource cts = new CancellationTokenSource();
                //        List<Task> taskList = new List<Task>();
                //        for (int i = 0; i < 50; i++)
                //        {
                //            string name = $"btnThreadCore_Click_{i}";
                //            taskList.Add(Task.Run(() =>
                //            {
                //                try
                //                {
                //                    if (!cts.IsCancellationRequested)
                //                        Console.WriteLine($"This is {name} 开始 ThreadId={Thread.CurrentThread.ManagedThreadId.ToString("00")}");
    
                //                    Thread.Sleep(new Random().Next(50, 100));
    
                //                    if (name.Equals("btnThreadCore_Click_11"))
                //                    {
                //                        throw new Exception("btnThreadCore_Click_11异常");
                //                    }
                //                    else if (name.Equals("btnThreadCore_Click_12"))
                //                    {
                //                        throw new Exception("btnThreadCore_Click_12异常");
                //                    }
                //                    else if (name.Equals("btnThreadCore_Click_13"))
                //                    {
                //                        throw new Exception("btnThreadCore_Click_13异常");
                //                    }
                //                    if (!cts.IsCancellationRequested)
                //                    {
                //                        Console.WriteLine($"This is {name}成功结束 ThreadId={Thread.CurrentThread.ManagedThreadId.ToString("00")}");
                //                    }
                //                    else
                //                    {
                //                        Console.WriteLine($"This is {name}中途停止 ThreadId={Thread.CurrentThread.ManagedThreadId.ToString("00")}");
                //                        return;
                //                    }
                //                }
                //                catch (Exception ex)
                //                {
                //                    Console.WriteLine(ex.Message);
                //                    cts.Cancel();
                //                }
                //            }, cts.Token));
                //        }
                //        //1 准备cts  2 try-catch-cancel  3 Action要随时判断IsCancellationRequested
                //        //尽快停止,肯定有延迟,在判断环节才会结束
    
                //        Task.WaitAll(taskList.ToArray());
                //        //如果线程还没启动,能不能就别启动了?
                //        //1 启动线程传递Token  2 异常抓取  
                //        //在Cancel时还没有启动的任务,就不启动了;也是抛异常,cts.Token.ThrowIfCancellationRequested
                //    }
                //    catch (AggregateException aex)
                //    {
                //        foreach (var exception in aex.InnerExceptions)
                //        {
                //            Console.WriteLine(exception.Message);
                //        }
                //    }
                //    catch (Exception ex)
                //    {
                //        Console.WriteLine(ex.Message);
                //    }
                //}
                #endregion
    
                #region 临时变量
                {
                    ////for (int i = 0; i < 5; i++)
                    ////{
                    ////    Task.Run(() =>
                    ////    {
                    ////        Console.WriteLine($"This is btnThreadCore_Click_{i} ThreadId={Thread.CurrentThread.ManagedThreadId.ToString("00")}");
                    ////    });
                    ////}
                    ////临时变量问题,线程是非阻塞的,延迟启动的;线程执行的时候,i已经是5了
                    ////k是闭包里面的变量,每次循环都有一个独立的k
                    ////5个k变量  1个i变量
                    //for (int i = 0; i < 5; i++)
                    //{
                    //    int k = i;
                    //    Task.Run(() =>
                    //    {
                    //        Console.WriteLine($"This is btnThreadCore_Click_{i}_{k} ThreadId={Thread.CurrentThread.ManagedThreadId.ToString("00")}");
                    //    });
                    //}
                }
                #endregion
    
                #region 线程安全&lock
                {
                    //线程安全:如果你的代码在进程中有多个线程同时运行这一段,如果每次运行的结果都跟单线程运行时的结果一致,那么就是线程安全的
                    //线程安全问题一般都是有全局变量/共享变量/静态变量/硬盘文件/数据库的值,只要多线程都能访问和修改
                    //发生是因为多个线程相同操作,出现了覆盖,怎么解决?
                    //1 Lock解决多线程冲突
                    //Lock是语法糖,Monitor.Enter,占据一个引用,别的线程就只能等着
                    //推荐锁是private static readonly object,
                    // A不能是Null,可以编译不能运行;
                    //B 不推荐lock(this),外面如果也要用实例,就冲突了
                    //Test test = new Test();
                    //Task.Delay(1000).ContinueWith(t =>
                    //{
                    //    lock (test)
                    //    {
                    //        Console.WriteLine("*********Start**********");
                    //        Thread.Sleep(5000);
                    //        Console.WriteLine("*********End**********");
                    //    }
                    //});
                    //test.DoTest();
    
                    //C 不应该是string; string在内存分配上是重用的,会冲突
                    //D Lock里面的代码不要太多,这里是单线程的
    
                    //2 线程安全集合
                    //System.Collections.Concurrent.ConcurrentQueue<int>
    
                    //3 数据分拆,避免多线程操作同一个数据;又安全又高效
    
                    //int iNumSync = 0;
                    //int iNumAsync = 0;
    
                    //for (int i = 0; i < 10000; i++)
                    //{
                    //    iNumSync++;
                    //}
                    //for (int i = 0; i < 10000; i++)
                    //{
                    //    Task.Run(() =>
                    //    {
                    //        iNumAsync++;
                    //    });
                    //    //Task.Run(() =>
                    //    //{
                    //    //    lock (Form_Lock)//任意时刻只有一个线程能进入方法块儿,这不就变成了单线程结果就是10000
                    //    //    {
                    //    //        iNumAsync++;
                    //    //    }
                    //    //});
                    //}
                    //iNumSync 和  iNumAsync分别是多少   10000  1到10000以内
    
    
                    //for (int i = 0; i < 10000; i++)
                    //{
                    //    int k = i;
                    //    Task.Run(() => this.iListAsync.Add(k));
                    //}
    
                    //Thread.Sleep(5 * 1000);
                    //Console.WriteLine($"iNumSync={iNumSync} iNumAsync={iNumAsync}");
    
                }
                #endregion
    
                #region lock this和lock string
                {
                    Test test = new Test();
                    ////lock同一个实例就会冲突 
                    //test.DoTest();
    
                    //Task.Delay(1000).ContinueWith(t =>
                    //{
                    //    lock (test) //DoTest方法执行完 才会执行这样
                    //    {
                    //        Console.WriteLine("*********Start**********");
                    //        Thread.Sleep(5000);
                    //        Console.WriteLine("*********End**********");
                    //    }
                    //});
    
                    //string在内存分配上是重用的,也会冲突
                    string student = "张三";
                    Task.Delay(1000).ContinueWith(t =>
                    {
                        lock (student)
                        {
                            Console.WriteLine("*********Start**********");
                            Thread.Sleep(5000);
                            Console.WriteLine("*********End**********");
                        }
                    });
                    test.DoTestString();
    
                }
                #endregion
    
                Console.ReadLine();
            }
    
            static readonly object Form_Lock = new object();
    
        }
    
        public class Test
        {
            /// <summary>
            /// 
            /// </summary>
            public void DoTest()
            {
                lock (this)
                //递归调用,lock this  不会死锁!
                //这里是同一个线程,这个引用就是被这个线程所占据
                {
                    Thread.Sleep(500);
                    this.iDoTestNum++;
                    if (DateTime.Now.Day < 28 && this.iDoTestNum < 10)
                    {
                        Console.WriteLine($"This is {this.iDoTestNum}次 {DateTime.Now.Day}");
                        this.DoTest();
                    }
                    else
                    {
                        Console.WriteLine("循环结束!!");
                    }
                }
            }
    
            public void DoTestString()
            {
                lock (this.Name)
                {
                    Thread.Sleep(500);
                    this.iDoTestNum++;
                    if (DateTime.Now.Day < 28 && this.iDoTestNum < 10)
                    {
                        Console.WriteLine($"This is {this.iDoTestNum}次 {DateTime.Now.Day}");
                        this.DoTestString();
                    }
                    else
                    {
                        Console.WriteLine("循环结束!!");
                    }
                }
            }
            private int iDoTestNum = 0;
            private string Name = "张三";
    
        }
  • 相关阅读:
    js代码的执行顺序及运算
    javascript讲解
    浏览器的差距
    标准流
    下拉列表
    单位
    滚动标签
    接着说一些有关排版的一些东西
    关于处理浏览器的兼容问题
    关于排版的技巧
  • 原文地址:https://www.cnblogs.com/wangdash/p/12261015.html
Copyright © 2011-2022 走看看