zoukankan      html  css  js  c++  java
  • 线程 线程池 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();
                }
            }
  • 相关阅读:
    C#匿名类与dynamic关键字有意思的玩法
    C#中参数化查询速度慢的原因
    拉姆达表达式的一些常用知识
    git的学习
    yield return的使用。。。
    C# Cache缓存的应用
    C# 异步编程,async与await的简单学习
    SSH
    SSM搭建手册
    PLsql快捷键
  • 原文地址:https://www.cnblogs.com/GZNETLGN/p/8949755.html
Copyright © 2011-2022 走看看