线程 线程池 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();
            }
        }

猜你喜欢

转载自www.cnblogs.com/GZNETLGN/p/8949755.html