執行緒 執行緒池 Task

劉Te發表於2018-04-26

首先宣告 這是讀了 愉悅的紳士 文章

菜鳥之旅——學習執行緒(執行緒和執行緒池)

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

 

相關文章