C#中异步多线程的实现方式

线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

一.通过委托的方式

委托中的Invoke方法完成一个委托方法的封送,在Invoke封送的方法被执行完毕前,Invoke方法不会返回,从而调用者线程将被阻塞。委托中的BeginInvoke方法是从ThreadPool取出一个线程来执行这个方法,以获得异步执行效果的。

        public delegate int AddDelegate(int a, int b);  //定义一个委托对象
        static void Main(string[] args)
        {
            Console.WriteLine("start");
            AddDelegate d1 = Add;
            //异步回调方法,异步方法执行完可以选择执行这个方法
            AsyncCallback cab = t =>
            {
                //Console.WriteLine(d1.EndInvoke(t));
                Console.WriteLine(t.AsyncState);    //可以获取传递过来的参数
                Console.WriteLine(t.IsCompleted);
            };

            IAsyncResult ar = d1.BeginInvoke(5,2,cab,12);    //前两个参数为引用方法传递的参数,cab为上面的回调方法,12为回调方法中的参数,执行BeginInvoke会返回一个IAsyncResult对象        
            Thread.Sleep(2000);
            int result = d1.EndInvoke(ar);           //该方法返回委方法中的真正返回值,该方法会阻塞主线程一直到异步执行完,EndInvoke只能被执行一次 
            Console.WriteLine("结果:"+result);

        }
        public static int Add(int a,int b)
        {
            return a + b;
        }       

 二.通过Thread类

 C#中的Thread类主要提供四个构造方法,ThreadStart是一个无参的委托,意味着我们能传递一个无参的方法进去。ParameterizedThreadStart是一个只有一个参数,参数类型为object的委托,我们可以传一个一个参数,参数类型为object的类型进去

     static void Main(string[] args)
        {
            //ThreadStart start1 = AddNoParms;
            //Thread thread1 = new Thread(start1);
            Thread thread1 = new Thread(AddNoParms);  //简化写法,直接传递与委托方法签名对应的方法
            Thread thread2 = new Thread(AddHasParms); //有参的形式
            thread1.Start();//开启这个线程
            thread2.Start("thread2");  //开启有参的Thread线程
            thread1.Name = "thread1";       //获取或设置线程的名称。
            thread1.IsBackground = true;   //获取或设置一个值,该值指示某个线程是否为后台线程。
            Thread.Sleep(2000); //让线程暂停一段时间。
            thread1.Abort();    //销毁线程
            Console.WriteLine(thread1.IsAlive);     //获取线程状态


            //获取异步回调的返回值
            int returndata = 0;     //声明一个变量用来接收异步方法执行的返回值
            ThreadStart threadstart = new ThreadStart
                (() =>{
                        returndata = Add(1, 2);
                        AddNoParms();
                    });
            Thread thread3 = new Thread(threadstart);
            thread3.Start();
            Console.WriteLine(returndata);
        }
        public static void AddHasParms(object str)
        {
            Console.WriteLine(str);
        }

        public static void AddNoParms()
        {
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
            Console.WriteLine("add");
        }
        public static int Add(int a,int b)
        {
            return a + b;
        }

 Thread类中还提供了许多属性和方法供我们使用

  //属性
      IsAlive   //获取一个值,该值指示当前线程的执行状态。
      IsBackground   //获取或设置一个值,该值指示某个线程是否为后台线程。前台进程跟后台进程的区别:程序关闭时,后台线程直接关闭,但前台线程会执行完后关闭。通过Thread类新建线程默认为前台线程。其他方式创建的都是后台线程。
      IsThreadPoolThread    //获取一个值,该值指示线程是否属于托管线程池。
      Priority    //获取或设置一个值,该值指示线程的调度优先级。
  //方法
      Abort    //在调用此方法的线程上引发 ThreadAbortException,以开始终止此线程的过程。调用此方法通常会终止线程。
      Join       //阻塞调用线程,直到某个线程终止为止。此方法有不同的重载形式
      ResetAbort    //取消为当前线程请求的 Abort。

 三.ThreadPool

ThreadPool类会在线程的托管池中重用已有的线程,一个应用程序最多只能有一个线程池,可以通过QueueUserWorkItem方法将工作函数排入进程池。QueueUserWorkItem有两个构造函数,WaitCallback是一个只有一个参数,参数类型为object的委托,我们可以传一个参数,参数类型为object的对象进行实例化

     static void Main(string[] args)
        {
       ThreadPool.SetMinThreads(1,1);
       ThreadPool.SetMaxThreads(1,5);
//调用方式一 用WaitCallback这个委托进行实例化 WaitCallback waitCallback = new WaitCallback(AddHasParms); ThreadPool.QueueUserWorkItem(waitCallback, "helloworld"); //调用方式二 传递与WaitCallback对应的方法进行实例化 ThreadPool.QueueUserWorkItem(AddHasParms,"helloworld"); //调用方法三 通过WaitCallback相对应的匿名方法,在匿名方法中进行调用 ThreadPool.QueueUserWorkItem(n=> { AddNoParms(); AddHasParms("helloworld"); }); } public static void AddHasParms(object str) { Console.WriteLine(Thread.CurrentThread.ManagedThreadId); Console.WriteLine(str); } public static void AddNoParms() { Console.WriteLine(Thread.CurrentThread.ManagedThreadId); }

 四.Task

     static void Main(string[] args)
        {
            //方式一   无返回值时
            Task task1 = new Task(AddHasParms, "helloworld");
            task1.Start();
            Task.WaitAll(task1);    //等待所有任务结束  
                    //有返回值时
            Task<int> task2 = new Task<int>(Add, "obj");
            task2.Start();
            Console.WriteLine(task2.Result);       //打印返回值

            //方式二    通过Run方法创建  无返回值
            Task.Run(() => AddHasParms("hello"));
            //无返回值时
            Task<int> task3 = Task.Run(() => Add("obj"));
            Console.WriteLine(task3.Result);

            //方式三 无返回值时
            Task.Factory.StartNew(() => AddHasParms("helloworld"));
            Task.WaitAll();
            //有返回值时
            var task4=Task.Factory.StartNew(() => Add("obj"));
            Console.WriteLine(task4.Result);


        }
        public static void AddHasParms(object str)
        {
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
            Console.WriteLine(str);
        }
        public static int Add(object a)
        {
            return  1;
        }

 

posted @ 2020-08-30 22:15  hello-*-world  阅读(1255)  评论(0编辑  收藏  举报