欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

线程 线程池 Task

程序员文章站 2022-07-02 14:36:47
首先声明 这是读了 愉悦的绅士 文章 《菜鸟之旅——学习线程(线程和线程池)》 《Task与线程》 的一些个人总结,还是那句话,如有不对,欢迎指正 文章以代码加注释的方法展示。 //线程的创建,阻塞和同步 //对方法加锁 //线程池 //Task 任务 推荐使用任务来做多线程的,便于管理 ......

首先声明 这是读了 愉悦的绅士 文章

菜鸟之旅——学习线程(线程和线程池)

Task与线程

的一些个人总结,还是那句话,如有不对,欢迎指正

文章以代码加注释的方法展示。

//线程的创建,阻塞和同步

   public static ManualResetEvent MREstop=new ManualResetEvent(false);
        public static AutoResetEvent AREstop = new AutoResetEvent(false);
       
        static void Main(string[] args)
        {
            //使用方法注册
            Thread Thread1 = new Thread(Method1);
            //使用Lambda注册
            Thread Thread2 = new Thread((s) =>
            {
                //暂停线程2,使用ManualResetEvent暂停,当使用Set方法的时候会跳过所有WaitOne();
                //MREstop.WaitOne();

                //暂停主线程,使用AutoResetEvent暂停,当使用Set方法的时候会跳过第一次遇到的WaitOne();
                AREstop.WaitOne();

                Console.WriteLine("----这是带参数方法2,参数为{0}----",s);
                Console.WriteLine(DateTime.Now);
                Console.WriteLine("----方法2结束----");

             
            });


            //若直接运行,会发现,Thread1和主线程的代码会交错在一起,而Thread2的代码一直在最后出现,这是因为Thread1和主线程一起运行,而Thread2延迟运行
            Thread1.Start();
            Thread2.Start("这是一个参数");

            //取消注释,会发现Thread1和Thread2都执行完后,才会执行主线程代码
            //Thread1.Join();
            //Thread2.Join();

            //暂停主线程,使用ManualResetEvent暂停,当使用Set方法的时候会跳过所有WaitOne();
            //MREstop.WaitOne();

            //暂停主线程,使用AutoResetEvent暂停,当使用Set方法的时候会跳过第一次遇到的WaitOne();
            //AREstop.WaitOne();

            Console.WriteLine("----这是主线程----");
            Console.WriteLine(DateTime.Now);
            Console.WriteLine("----主线程结束----");

        }

     static void Method1()
        {
           
            Thread.Sleep(1000);
            Console.WriteLine("----这是不带参数方法1----");
            Console.WriteLine(DateTime.Now);
            Console.WriteLine("----方法1结束----");

            //使用线程1开启同步,当使用Set方法的时候会跳过所有WaitOne();
            //MREstop.Set();

            //使用线程1开启同步,,当使用Set方法的时候会跳过第一次遇到的WaitOne(),所以主要是看Cpu先执行那个进程;
            //AREstop.Set();
        }

//对方法加锁

   static readonly object LockObject = new object();
        static int i = 100;
        static void Main(string[] args)
        {
            //实例化100条线程,执行同一个方法
            for (int i = 0; i < 100; i++)
            {
                Thread Thread1 = new Thread(Method1);
                Thread1.Start();
            }

        }

        static void Method1()
        {
            //若不加锁,所有线程都可以同时访问该方法,会造成显示的结果混乱,而加了锁,就同时只能拥有一个线程访问该方法
            //Monitor.Enter(LockObject);

            //i++非原子性操作,可能同时被多个线程执行,造成竞态,会影响运算结果,所以不能在多线程中使用。
            //i++;

            //推荐使用线程原子性自增操作
            System.Threading.Interlocked.Increment(ref i);

            Thread.Sleep(10);
            Console.WriteLine("This is Thread{0} and i={1}", Thread.CurrentThread.ManagedThreadId, i);
            Console.WriteLine("--------------------------------");
            //加了锁必须解锁
            //Monitor.Exit(LockObject);


            //或者使用lock(LockObject)的方法,相当于try{Monitor.Enter(LockObject);}catch{}finally{Monitor.Exit(LockObject);}的简便写法
            //lock(LockObject)
            //{
            //    System.Threading.Interlocked.Increment(ref i);
            //    Thread.Sleep(10);
            //    Console.WriteLine("This is Thread{0} and i={1}", Thread.CurrentThread.ManagedThreadId, i);
            //    Console.WriteLine("--------------------------------");
            //}


        }

//线程池

public static AutoResetEvent AREstop1 = new AutoResetEvent(false);
        static void Main(string[] args)
        {
            AutoResetEvent AREstop2 = new AutoResetEvent(false);

            //创建并且执行,线程池上限为CPU核心数*250,默认为后台线程
            ThreadPool.QueueUserWorkItem(new WaitCallback(Method1), AREstop2);

            //创建并且执行
            ThreadPool.QueueUserWorkItem(new WaitCallback(s =>
            {
                Thread.Sleep(2000);
                Console.WriteLine("----这是带参数方法2,参数为{0}----", s);
                Console.WriteLine(DateTime.Now);
                Console.WriteLine("----方法2结束----");
                AREstop1.Set();
            }), "这是一个参数");


            //线程池的同步线程和线程一致,可以使用ManualResetEvent和AutoResetEvent执行。

            //由于线程池没有Join方法,所以可以使用WaitAll()方法来达到所有线程执行完毕后执行主线程的效果
            List<WaitHandle> handles = new List<WaitHandle>();
            handles.Add(AREstop1);
            // handles.Add(AREstop2);
            //注意,对多个线程要使用不同的AutoResetEvent,只要数组中的AutoResetEvent接受到set指令就解锁,若全部为同一个名字
            //则只要任何一个进程set之后,就会执行主线程。由于线程池默认为后台线程,一旦执行完成主线程,则其余线程自动结束
            //必须数组之中的AutoResetEvent全部set后才会执行,如果该有一个没有set,都不会执行主线程。
            //WaitAll最大数组上限为64
            WaitHandle.WaitAll(handles.ToArray());

            Console.WriteLine("----这是主线程----");
            Console.WriteLine(DateTime.Now);
            Console.WriteLine("----主线程结束----");
        }

        //方法要带一个参数
        static void Method1(object obj)
        {
            Thread.Sleep(1000);
            Console.WriteLine("----这是带参数方法1----");
            Console.WriteLine(DateTime.Now);
            Console.WriteLine("----方法1结束----");
            AutoResetEvent AREstop2 = (AutoResetEvent)obj  ;
            AREstop2.Set();
        }

 //Task 任务  推荐使用任务来做多线程的,便于管理

  public static AutoResetEvent AREstop1 = new AutoResetEvent(false);
        static void Main(string[] args)
        {
            //Task实例化的都是后台线程,如果要更改为前台线程,需要再方法里面修改


            #region Task任务 使用线程池
            //{
            //    //实例化任务,必须手动启动,注意,方法是不能带参数的
            //    Task TaskFirst = new Task(Method1);

            //    //Status可以标识当前任务的状态
            //    //Created:表示默认初始化任务,但是“工厂创建的”实例直接跳过。
            //    //WaitingToRun: 这种状态表示等待任务调度器分配线程给任务执行。
            //    //RanToCompletion:任务执行完毕。
            //    Console.WriteLine("TaskFirst的状态:{0}", TaskFirst.Status);

            //    TaskFirst.Start();

            //    Console.WriteLine("TaskFirst的状态:{0}", TaskFirst.Status);

            //    //工厂创建的直接执行
            //    Task TaskSecond = Task.Factory.StartNew(() =>
            //    {

            //        Console.WriteLine("----这是不带参数方法2----");
            //        Console.WriteLine(DateTime.Now);
            //        Console.WriteLine("----方法2结束----");
            //    });

            //    //使用这种方法删除任务
            //    //CancellationTokenSource cancelTokenSource = new CancellationTokenSource();
            //    //Task.Factory.StartNew(() =>
            //    //{

            //    //    Console.WriteLine("----这是要删除方法4----");
            //    //    Console.WriteLine(DateTime.Now);
            //    //    Console.WriteLine("----要删除方法结束----");
            //    //}, cancelTokenSource.Token);
            //    //cancelTokenSource.Cancel();



            //    //流程控制
            //    {
            //        //没有加标识的默认使用线程池创建,若主线程结束自动结束,所以需要先堵塞主线程
            //        //AREstop1.WaitOne();

            //        //或者使用阻塞
            //        Task.WaitAll(TaskFirst, TaskSecond);

            //        //也可以使用Wait()等待单个线程,你会发现下面TaskFirst的状态的状态为Running,因为主线程开始运行了,而线程TaskFirst还在运行中
            //        //TaskSecond.Wait();

            //        //Task.WaitAny 只要数组中有一个执行完毕,就继续执行主线程
            //        //Task.WaitAny(TaskFirst, TaskSecond);

            //        //继续执行,在TaskFirst任务结束后继续执行,此时TaskFirst已经结束。记得加Wait(),否则主线程结束就直接结束了。
            //        TaskFirst.ContinueWith(NewTask =>
            //        {
            //            Console.WriteLine("----这是不带参数方法3----");
            //            Console.WriteLine(DateTime.Now);
            //            Console.WriteLine("TaskFirst的状态:{0}", TaskFirst.Status);
            //            Console.WriteLine("----方法3结束----");
            //        }).Wait();

            //    }

            //    Console.WriteLine("TaskFirst的状态:{0}", TaskFirst.Status);
            //}
            #endregion


            #region Task任务 使用线程
            {
                ////实例化任务,必须手动启动,注意,方法是不能带参数的
                //Task TaskFirst = new Task(Method1, TaskCreationOptions.LongRunning);
                //TaskFirst.Start();
            }
            #endregion


            #region Task任务 带参数
            {
                Task<int> TaskFirst = new Task<int>(((x) => { return (int)(x); }), 10);
                TaskFirst.Start();
                Console.WriteLine(" result ={0}", TaskFirst.Result);

                Task<string> TaskSecond = Task<string>.Factory.StartNew(new Func<object, string>(x => { return $"This is {x}"; }), 10);
                Console.WriteLine(" result ={0}", TaskSecond.Result);
            }
            #endregion

            Console.WriteLine("----这是主线程----");
            Console.WriteLine(DateTime.Now);
            Console.WriteLine("----主线程结束----");

        }

        //C# 6.0只读赋值
        static object Locker { get; } = new object();
        static void Method1()
        {
            lock (Locker)
            {
                Thread.CurrentThread.IsBackground = false;
                Thread.Sleep(1000);
                Console.WriteLine("----这是带参数方法1----");
                Console.WriteLine(DateTime.Now);
                Console.WriteLine("----方法1结束----");
                //AREstop1.Set();
            }
        }