C#秘密武器之多线程——基础

 多线程概述

什么是进程?

      当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源。而一个进程又是由多个线程所组成的。

什么是线程?

      线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区是共享的,即不同的线程可以执行同样的函数。

什么是多线程?

     多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。

多线程的好处

      可以提高CPU的利用率。在多线程程序中,一个线程必须等待的时候,CPU可以运行其它的线程而不是等待,这样就大大提高了程序的效率。

多线程的不利方面

     线程也是程序,所以线程需要占用内存,线程越多占用内存也越多; 多线程需要协调和管理,所以需要CPU时间跟踪线程; 线程之间对共享资源的访问会相互影响,必须解决竞用共享资源的问题;线程太多会导致控制太复杂,最终可能造成很多Bug;

.NET中的多线程

一、创建线程

我们可以使用Thread类的构造函数创建线程,用无参数的TheadStart委托或者带有一个参数的ParameterizedTheadStart委托作为构造函数的参数即可。线程执行其实就是执行里边的线程函数——即里边的委托函数!

public delegate void ThreadStart();  
public delegate void ParameterizedThreadStart(object obj);

举个栗子:

static void Main()  
{  
    Thread t = new Thread(new TheadStart(Go));
    //Thread t = new Thead(Go);
    t.Start();  
}  
static void Go()  
{  
    Console.Write("hello!");  
}  

static void Main()  
{  
    Thread t = new Thread(Go);  
    t.Start("hello");  
    Go();  
}  
static void Go(object msg)  
{  
    string message = (string)msg;  
    Console.Write(message);  
}  

二、启动线程

start():将当前线程的状态更改为 ThreadState.Running。

一旦线程处于 ThreadState.Running 状态,操作系统就可以安排其执行。 线程从方法的第一行(由提供给线程构造函数的 ThreadStart 或 ParameterizedThreadStart 委托表示)开始执行。线程一旦终止,它就无法通过再次调用 Start 来重新启动。

三、线程睡眠

Thread.Sleep(int ms);
Thread.Sleep(TimeSpan timeout);

上述方法为Thread类的两个静态方法,用来阻止当前线程指定的时间。

四、终止线程

使用Abort方法实现,用于永久地停止托管线程。一旦线程被中止,它将无法重新启动。Abort会引发ThreadAbortException异常,同时可以传递一个终止的参数信息。

Thread.Abort();
Thread.Abort(Object  stateInfo);

注意:Suspend和Resume为废弃方法,不要使用!

五、线程属性

5.1、线程名字

每个线程都有一个Name属性,可以设置和修改,但是只能设置一次。

5.2、后台线程

在.net中线程分为前台线程和后台线程,在一个进程中,当所有前台线程停止运行时,CLR会强制结束仍在运行的任何后台线程,这些后台线程直接被终止,不会抛出异常。所以我们应该在前台线程中执行我们确实要完成的事情!

static void Main(string[] args)
{
    Thread t = new Thread(Test);
    t.IsBackground = true;
    //这里线程是后台线程,应用程序马上结束
    //假如是前台线程,大约5秒以后结束
    t.Start();
    Console.WriteLine("A");
}
static void Test()
{
    Thread.Sleep(5 * 1000);
    Console.WriteLine("B");
}

5.3、线程优先级

线程的优先级使用Priority设置或获取,只有在运行时才有作用,分为5个级别:

enum ThreadPriority{Lowest, BelowNormal , Normal, AboveNormal, Highest}

举个栗子:

myThread.Priority=ThreadPriority.Lowest;

注意:优先等级高的线程占用更多的CUP时间。 但是当优先等级高的线程正在等待一些资源的时候,优先等级低的线程可以运行。

六、阻塞线程

阻塞某个线程用的方法是join()。这个方法可以让并发处理变得串行化,让主线程去等待某个线程执行完毕才继续往下执行!

class Test
{
    static void Main()
    {
        Thread t = new Thread(Run);

        t.Start();

        //Join相当于把Run方法内嵌如此
        t.Join();

        //该死的t.Join(),害的我主线程必须在你执行完后才能执行。
        Console.WriteLine("我是主线程:" + Thread.CurrentThread.GetHashCode());
    }

    static void Run()
    {
        //等待5s
        Thread.Sleep(5000);

        Console.WriteLine("我是线程:" + Thread.CurrentThread.GetHashCode());
    }
}

七、线程的异常处理

线程的异常都是在线程函数里边解决的,因此应该把try catch放在线程的委托函数里边~

static void Main(string[] args)  
{  
    try  
    {  
        new Thread(Go).Start();  
    }  
    catch (Exception ex)  
    {  
        Console.Write(ex.Message);  
    }  
      
    Console.ReadKey();  
}  
static void Go()  
{  
    try  
   {  
          ///处理逻辑  
    }
   catch(Exception e)
    {  
          Console.Write(e.Message);  
    }  
}  

注意:在调用Abort方法终止一个线程时,在异常处理的时候为了防止程序再次抛出异常,在catch里边处理完异常之后最好加上Thread.ResetAbort();这条语句!

原文地址:https://www.cnblogs.com/WeiGe/p/4237815.html