線程 線程池 Task

首先聲明 這是讀了 愉悅的紳士 文章html

菜鳥之旅——學習線程(線程和線程池)數組

Task與線程多線程

的一些我的總結,仍是那句話,若有不對,歡迎指正學習

文章以代碼加註釋的方法展現。spa

//線程的建立,阻塞和同步線程

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

//對方法加鎖code

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


        }

//線程池htm

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 任務  推薦使用任務來作多線程的,便於管理blog

  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();
            }
        }
相關文章
相關標籤/搜索