• C# 看懂这100+行代码,你就真正入门了(经典)


    老铁

    先不废话,简单粗暴,直接来源码:

    using System;using System.Collections.Concurrent;using System.Collections.Generic;using System.Threading;using System.Threading.Tasks;using System.Windows.Forms;
    namespace TestConsole{    class Program    {        private static ManualResetEvent manualResetEvent = new ManualResetEvent(false);//AutoResetEvent略去        //private static List<int> list = new List<int>();//非线程安全,“集合已修改;可能无法执行枚举操作。”        private static ConcurrentBag<int> list = new ConcurrentBag<int>();        private static CancellationTokenSource cancellationToken = new CancellationTokenSource();        private static ConcurrentDictionary<int, string> concurrentDictionary = new ConcurrentDictionary<int, string>();        private static ConcurrentQueue<int> concurrentQueue = new ConcurrentQueue<int>();        static void Main(string[] args)        {            try            {                //ThreadSafetyTest();                //ManualResetEventHandler();                //DelegateTest();                TasKTest();
                    Console.ReadKey();            }            catch (Exception ex)            {                MessageBox.Show(ex.StackTrace + " " + ex.Message);            }        }        #region TASK用法举例        static void TasKTest()        {            //带返回值的task            Task<String> mytask = Task.Run(async () =>            {                await Task.Delay(5000);                return "老铁666";            }, cancellationToken.Token);            //cancellationToken.Cancel();            while (!mytask.Wait(100)) //在指定时间执行完成就返回true            {                Console.Write(".");            }            Console.WriteLine(mytask.Result);//task任务取消,所以获取task.Result会报错
                Task taskFactory = Task.Factory.StartNew(() =>            {                Thread.Sleep(1000);                Console.WriteLine("perfect!");            });            Console.WriteLine(taskFactory.Status);            taskFactory.Wait();//taskFactory任务完成才往下执行            Task.WaitAll(mytask, taskFactory);//所有任务完成再往下执行            Task.WaitAny(mytask, taskFactory);//任一任务完成就往下执行            Console.WriteLine(taskFactory.Status);
                Task taskTest = taskFactory.ContinueWith(DoOnSecond);//ContinueWith用法举例        }        static void DoOnSecond(Task t)        {            Console.WriteLine("task {0} finished", t.Id);            Console.WriteLine("this task id {0}", Task.CurrentId);            Console.WriteLine("do some cleanup");        }        #endregion
            #region ManualResetEvent 用法举例        private static void ManualResetEventHandler()        {            Thread t1 = new Thread(Thread1);            t1.Start();            Thread t2 = new Thread(Thread2);            t2.Start();            Thread.Sleep(2000);            manualResetEvent.Set();            Thread.Sleep(5000);            t1.Abort();//放弃执行线程t1            Console.WriteLine(t1.ThreadState);            Console.WriteLine(t2.ThreadState);        }        static void Thread1()        {            Console.WriteLine(manualResetEvent.WaitOne().ToString());//等待 manualResetEvent.Set()后执行            manualResetEvent.Reset();// 将信号置为初始状态,即false            //Console.WriteLine(manualResetEvent.WaitOne().ToString());//阻塞当前线程,让他等待着            MessageBox.Show("Thread1 run end");            Parallel.For(0, 100000000, item =>            {                Console.WriteLine(item.ToString());            });        }
            static void Thread2()        {            Console.WriteLine(manualResetEvent.WaitOne(10000).ToString());//10秒内收到 manualResetEvent.Set(),即true就往下执行,或者超过100秒,也往下执行,但是状态依然为false            MessageBox.Show("Thread2 run end");        }        #endregion
            #region 线程安全之ConcurrentBag 验证        private static void ThreadSafetyTest()        {            int count = 0;            Task t = new Task(() =>            {                while (true)                {                    Thread.Sleep(1000);                    count++;                    list.Add(count);                }            });            t.Start();
                Task.Run(() =>            {                while (true)                {                    foreach (var item in list)                    {                        Thread.Sleep(1000);                        Console.WriteLine($"{list.Count}");                    }                }            });
            }        #endregion
            public static void DelegateTest()        {            Func<string, string> RetBook = new Func<string, string>(FuncBook);            Console.WriteLine(RetBook("《平凡的世界》"));
            }        public static string FuncBook(string BookName)        {            return BookName;        }
    
        }}
    
    

    上面代码逻辑要是全懂了,下面就可以跳过了,

    没看懂的继续。。。。。。。

    ① 首先,执行第一个方法ThreadSafetyTest();

    涉及知识点:

    1. task的创建和使用;

    2. foreach遍历 

    3. 线程安全集合ConcurrentBag用法

    修改这里后运行:

                    ThreadSafetyTest();                //ManualResetEventHandler();                //DelegateTest();                //TasKTest();              

    执行结果如下:

    这个方法体的作用主要是开了两个线程,第一个线程每隔1秒向集合添加一个数,第二个线程每隔一秒,便利输出集合。在这里集合要是改成list的,即:

    private static ConcurrentBag<int> list = new ConcurrentBag<int>(); 改成=>private static List<int> list = new List<int>();

    运行过程会报错:

    非线程安全,“集合已修改;可能无法执行枚举操作。”

    原因解释:不管是读还是写,同一时刻只能做一件事情,要么读,要么写,多个线程对同一个集合进行读写操作,就难免会出现线程安全问题,当然你可以

    用lock关键字,进行线程同步,但是性能并不是特别理想,然后我尝试使用SynchronizedList来代替使用List达到线程安全的目的。但是发现性能依旧糟糕,于是查看了SynchronizedList的源代码,发现它就是简单的在List提供的API的基础上加了lock,所以性能基本与list方式相差无几。最后使用ConcurrentBag类来实现,性能有很大的改观。

    知识拓展:线程安全的队列和字典:

     ConcurrentDictionary<int, string> concurrentDictionary = new ConcurrentDictionary<int, string>(); ConcurrentQueue<int> concurrentQueue = new ConcurrentQueue<int>();

    ② 接下来,执行第二个方法ManualResetEventHandler();

    涉及知识点:

    1. ManualResetEvent用法(和AutoResetEvent类似,区别自己去学习);

      主要包括:

      manualResetEvent.Reset();    manualResetEvent.Set();

      manualResetEvent.WaitOne()和manualResetEvent.WaitOne(time)

    2. Thread线程创建和使用;

      重点解释:

      Console.WriteLine(manualResetEvent.WaitOne(10000).ToString());10秒内收到 manualResetEvent.Set(),即true就往下执行,或者超过100秒,也往下执行,但是状态依然为false

      最后的执行结果:

    ③ 接下来,执行第三个方法DelegateTest();

    知识点:带参数,带返回值的委托Func的用法

    运行结果:

    总结一下 :无返回就用action,有返回就用Func

    ④ 最后,执行第四个方法DelegateTest();

    涉及知识点:

    1. task的创建和使用前面已经提供了两种创建方式,这里又提供了新的方式Task.Factory.StartNew(() =>{});

    2. 取消task任务之CancellationTokenSource的用法;

    3. task的线程管控方法Task..Wait(time),Task.WaitAll(), Task.WaitAny(),task.ContinueWith.

    运行结果:


    原创不易,用100+行代码串接这么多重要知识点更加不易。

    老铁666

    老铁到底溜不溜,在看转发走起来!

    进技术交流群的,加小编微信zls20210502,切记备注:进群!

    项目工程下载地址:
    链接: https://pan.baidu.com/s/1MEm-CjQjrReP6jxyqpLjQA 

    提取码: wr3n 

  • 相关阅读:
    各种二端口滤波器网络仿真遇到的问题
    (已解决)在服务器(linux,centos)中调用R绘制图形之后保存报错,而在Windows中正常
    MySQL 索引分类
    XFS 打开电子商务新方式
    【Go之道】探索Go语言之旅:基础与进阶指南
    2022-10-27-梯度下降法结合线性回归预测公交车数量和GDP关系
    原型链污染攻击
    c++ vector的模拟实现以及迭代器失效问题
    【CMU15-445 Part-9】Multi-Threaded Index Concurrency Control
    八大排序(四)--------直接插入排序
  • 原文地址:https://blog.csdn.net/biyusr/article/details/125873184