C#

C# 线程

Posted by Kerwen Blog on January 3, 2018

线程生命周期

线程生命周期开始于 System.Threading.Thread 类的对象被创建时,结束于线程被终止或完成执行时。
下面列出了线程生命周期中的各种状态:

未启动状态: 当线程实例被创建但 Start 方法未被调用时的状况。
就绪状态: 当线程准备好运行并等待 CPU 周期时的状况。
不可运行状态: 下面的几种情况下线程是不可运行的:
已经调用 Sleep 方法
已经调用 Wait 方法
通过 I/O 操作阻塞
死亡状态: 当线程已完成执行或已中止时的状况。

主线程

在 C# 中,System.Threading.Thread 类用于线程的工作。它允许创建并访问多线程应用程序中的单个线程。进程中第一个被执行的线程称为主线程。
当 C# 程序开始执行时,主线程自动创建。使用 Thread 类创建的线程被主线程的子线程调用。您可以使用 Thread 类的 CurrentThread 属性访问线程。
Example:

1
2
3
4
5
6
7
static void Main(string[] args)
{
    Thread th = Thread.CurrentThread;
    th.Name = "MainThread";
    Console.WriteLine("This is {0}", th.Name);
    Console.ReadKey();
}

运行结果:

1
This is MainThread

创建线程

1
2
3
4
5
6
7
8
9
10
11
12
static void Main(string[] args)
{
    Thread t = new Thread(Child);
    t.Start();
    Console.WriteLine("This is main thread.");
    Console.ReadKey();
}

static void Child()
{
    Console.WriteLine("This is in thread.");
}

运行结果:

1
2
This is main thread.
This is in thread.

程序运行的结果不能保证哪个先输出,因为线程是由操作系统调度,每次哪个线程在前面可以不同

线程管理

Sleep()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
static void Main(string[] args)
{
    Thread t = new Thread(Child);
    t.Start();
    Console.WriteLine("This is main thread.");
    Console.ReadKey();
}

static void Child()
{
    Console.WriteLine("This is in thread.");
    Thread.Sleep(1000);
    Console.WriteLine("Sleep 1 second.");
}

传入参数

1
2
3
4
5
6
7
8
9
10
11
static void Main(string[] args)
{
    Thread t2 = new Thread(ChildWithParam);
    t2.Start("test");
    Console.ReadKey();
}

static void ChildWithParam(object str)
{
    Console.WriteLine("Child with parameter: " + str.ToString());
}

上面创建的线程是类型不安全的,那用什么样的方式执行带传入参数的线程的方法是类型安全的呢,答案就是创建一个自定义类,在类中定义一个作为传入参数的字段,将线程的主方法定义为一个类的实例方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
static void Main(string[] args)
{
    ThreadClass<string> testClass = new ThreadClass<string>("data");
    Thread t3 = new Thread(testClass.ThreadFun);
    t3.Start();
    Console.ReadKey();
}

class ThreadClass<T>
{
    private T data;
    public ThreadClass(T data)
    {
        this.data = data;
    }

    public void ThreadFun()
    {
        Console.WriteLine("In thread class: " + this.data.ToString());
    }
}

后台线程  

  Thread类默认创建的是前台线程,所以我们前面创建的线程全部都是前台线程。只要有一个前台线程在运行,应用程序的进程就在运行。如果有多个前台线程在运行,而Main()方法(主线程)结束了,应用程序的进程就仍然是激活的,直到所有前台线程完成其任务为止。
  那后台线程呢?显然和前台线程相反。当主线程结束后,应用程序的进程就终止了,在所有前台线程结束后,后台线程就会被终止。
  在编码的时候我们可以设置Thread类的IsBackground的属性来确定该线程是前台线程还是后台线程。当IsBackground设置为False的时候,为前台线程,设置为Ture的时候为后台线程。

线程池

线程池是可用于在后台执行多种任务的线程集合。
线程池通常用于服务器应用程序。 每个传入请求都将分配给线程池中的一个线程,因此可以异步处理请求,而不会占用主线程,也不会延迟后续请求的处理。 一旦池中的线程完成任务,它将返回到等待线程队列中,等待被重复使用。 通过这种重复使用,应用程序可以避免产生为每个任务创建新线程的开销。
线程池通常具有最大线程数限制。 如果所有线程处于忙碌状态,则额外的任务将放入队列中,直到有线程可用时才能够得到处理

LR线程池

线程同步

Task类

线程异步