• 语法之多线程


    上一章中笔者对C#一些独有的语法点进行讲解,相信也可以看C#的一些神奇之处。那么本章主要是放在多线程这方面的知识。不管是C#还是JAVA在开发过程或多或少都会用到关于多线程的编程。当然笔者不可能把多线程的知识点讲的很全面。笔者这里只是讲一些笔者常用到的。如果有兴趣的朋友,笔者希望主动性去查找一下资料。

    Thread类

    对于Thread类相信JAVA的朋友一点也不陌生。在一点上C#到是跟JAVA很类似。只是在使用上有一定差别。首先要明白C#的多线程功能一般都是在命名空System.Threading下面。至于什么是线程,进程又是什么这样子的问题。笔者就不多说了。相信大家都明白。笔者还是喜欢直接一点。让我们看一下代码进行学习吧。

    C#:

    复制代码
     1  class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5             Thread myThread1 = new Thread(() =>
     6             {
     7                 Console.WriteLine("这是一个lambda表达式 创建线程");
     8             });
     9 
    10             Thread myThread2 = new Thread(ThreadStartImp);
    11 
    12             Thread myThread3 = new Thread((object obj) =>
    13             {
    14                 Console.WriteLine("这是一个lambda表达式创建有参数的线程 参数:" + obj.ToString());
    15             });
    16 
    17             myThread1.Start();
    18             myThread2.Start();
    19             myThread3.Start("aomi");
    20 
    21         }
    22 
    23         public static void ThreadStartImp()
    24         {
    25             Console.WriteLine("这是一个用方法创建线程");
    26         }
    27 
    28 
    29     }
    复制代码

    笔者在上面创建三个线程代码。myThread1和myThread2是同一种线程。即是没有参数的线程。myThread3是有参数的线程。不管是不是有参数。使用方式基本是一样子的。有参数的话,就是调用Start方法的时候给他传入一个参数即可。我们可以看到使用上跟JAVA有一个很大的差别。JAVA的Thread类构造函数的参数传入Runnable接口。可惜C#不是。如下代码。

    C#:

    public Thread(ParameterizedThreadStart start);
    public Thread(ThreadStart start);
    public Thread(ParameterizedThreadStart start, int maxStackSize);
    public Thread(ThreadStart start, int maxStackSize);

    这段代码是源码里面的。选中Thread类按F12就可以大概的查看Thread类的结构。我们看可以看到四个构造函数。我们常常用到只是俩个:Thread(ParameterizedThreadStart start)和Thread(ThreadStart start)。刚刚看到的时候我一直以为ThreadStart会跟JAVA的Runnable接口一样子。只到按F12进入查看一下结构才明白大错特错。如下代码

    C#:

    [ComVisible(true)]
    public delegate void ThreadStart();

    C#:

    [ComVisible(false)]
    public delegate void ParameterizedThreadStart(object obj);

    我们可以清楚的看到一个关键字delegate。相信有看过上一章的朋友都知道他是跟事件有关系。没有错。就是定义一个委托类型。以便将来用于传方法。所以我们可以明白这边的Thread类的构造函数的参数只能传入方法。那么相信笔者上面的三个线程的定义的意义也很明显了。

    myThread1线程:笔者用的是lambda表达式来创建。lambda表达是什么上一章也有简单的讲到。

    myThread2线程:外面定义一个方法用于实现多线程。这方法可以是一个静态方法也可以是一个对象的方法。关键字static的功能跟JAVA一样子。

    myThread3线程:实现有一个有参数的多线程。

    上面只是讲到关于Thread类的使用。对于Thread类对象里面的一些方法的话,笔者就不多介绍了。大至跟JAVA的Thread类一样子。如Interrupt方法。请读者们自行查看。

    ThreadPool类

    当我们谈到多线程池的时候,相信大家都知道是什么东西。C#用的是ThreadPool类。只是可惜笔者在JAVA这边用到多线程池的机会不多。所以也不清楚JAVA中的ThreadPoolExecutor类和Executors类跟C#的ThreadPool类相差多少。不过有兴趣的朋友可以看一下。笔者这里还是讲一下ThreadPool类的使用吧。ThreadPool类更多的时候有一点像工具类一样子。如下面代码。

    C#:

    复制代码
     class Program
        {
            static void Main(string[] args)
            {
                ThreadPool.QueueUserWorkItem((obj) =>
                {
                    Console.WriteLine("这是一个lambda表达式创建有参数的线程 参数:" + obj.ToString());
                });
    
                ThreadPool.QueueUserWorkItem(WaitCallbackImp);
    
            }
    
            public static void WaitCallbackImp(object obj)
            {
                Console.WriteLine("这是一个用方法创建线程");
            }
        }
    复制代码

    上面的代码跟上面的Thread类有一点类似。可是本质上却有很大的差别。这里是用多线程池的。另外对于多线程池的设置。只要ThreadPool.XXXXX里面有很多方法让你去设置。

    Task类

    如果你们有用上面的Thread类你就会发现,有时候当线程在运行中的时候很难停止。但是如果你用了Task类的话,你就会发现这个难点已经不存在了。我也不清楚C#为什么会引入Task类。可能就是因为Thread类和ThreadPool类太难控制吧。那么这不是笔者关注的问题。让我们看一下Task类是如何使用的。Task类是中文常常叫做任务。所以就是有一种说法。是单任务还是多任务。为什么笔者会这样子讲呢?如下。

    1.单任务。即是一个Task类实例。这个时候就比较简单。代码如下

    复制代码
      class Program
        {
            static void Main(string[] args)
            {
                CancellationTokenSource cts = new CancellationTokenSource();//用于中途取消
                Task myTask = new Task((obj) =>
                {
                    Console.WriteLine("这是一个单任务");
                }, cts);
                myTask.Start();
    
                Console.ReadKey();
            }
        }
    复制代码

    这里面笔者只用到了一个类CancellationTokenSource。这个类就是用于取消任务。还是让笔者写一个例子吧。

    复制代码
     class Program
        {
            static void Main(string[] args)
            {
                CancellationTokenSource cts = new CancellationTokenSource();//用于中途取消
                Task myTask = new Task((obj) =>
                {
                    
                    Console.WriteLine("这是一个单任务");
    
                    Thread.Sleep(20000);//让他睡一段时间
                }, cts);
    
                myTask.Start();
    
                if (cts.IsCancellationRequested)//判断是否取消
                {
                    cts.Cancel();
                }
    
                Console.ReadKey();
            }
        }
    复制代码

    2.多任务。就是多个Task类的实例进行配合。这个时候就有谁先做。谁后做的问题。

    复制代码
     class Program
        {
            static void Main(string[] args)
            {
                CancellationTokenSource cts1 = new CancellationTokenSource();//用于中途取消
                Task myTask1 = new Task((obj) =>
                {
                    
                    Console.WriteLine("这是一个单任务");
    
                    //Thread.Sleep(20000);//让他睡一段时间
                }, cts1);
    
                CancellationTokenSource cts2 = new CancellationTokenSource();//用于中途取消
    
                myTask1.ContinueWith((task) => {
    
                    Console.WriteLine("myTask2任务");
                }, cts2.Token);
    
                myTask1.Start();
    
                //if (cts1.IsCancellationRequested)//判断是否取消
                //{
                //    cts1.Cancel();
                //}
    
                Console.ReadKey();
            }
        }
    复制代码

    上面的ContinueWith方法就是表示:当myTask1结束之后,就可以继续红色的代码。即是另一个Task任务。除了上面的实例之后,还有一种用法。代码如下。

    复制代码
    CancellationTokenSource cts3 = new CancellationTokenSource();//用于中途取消
    Task.Factory.StartNew((obj) =>
    {
    
       Console.WriteLine("这是一个用的Factory单任务");
    
    }, cts3);
    复制代码

    看样了不用笔者多说了。有一点类似于多线程池的概念。只是注意Task.Factory里面还有一些很好用的功能。ContinueWhenAll方法就是一个很好的体现。和上面的ContinueWith有一个像。即是所以的task结束之后才执行对应的最后一个task。请用Task.Factory.让他提示进行学习。如果不提示的话,写完上面的"ask.Factory."之后按Ctrl+J。里面有各种方法让你学习。

    本章总结

    本章主要是对多线程常用的一些知识进行讲解。笔者并没有对他们进行详细的说明。所以希望读者们可以根据笔者所讲的继续深入下去。

  • 相关阅读:
    C++11 vector使用emplace_back代替push_back
    Centos6.4 编译安装 nginx php
    Centos 编译安装nodejs&express框架
    zookeeper 入门(二)
    zookeeper 入门(一)
    Paxos算法1-算法形成理论[转载]
    yum只下载软件不安装的两种方法
    Centos 6.4 安装dnsmasq
    Centos 6.4 安装erlang&rabbitmq
    Centos 6.4 安装Python 2.7 python-pip
  • 原文地址:https://www.cnblogs.com/sjqq/p/6777293.html
Copyright © 2020-2023  润新知