Thread 多线程介绍

概念

什么是线程?

线程是操作系统中能够独立运行的最小单位,也是程序中能够并发执行一段指令的序列。
线程是进程的一部分,一个进程可以包含多个线程,这些线程共享进程的资源。
进程又入口线程,也可以创建更多的线程。

为什么要多线程?

批量重复任务希望同时执行(比如:对一个数组中的每个元素都同时进行且耗时的操作)
多个不同任务希望同时进行,互不干扰(比如又多个后台线程需要做轮询等操作)

什么是线程池?

一组预先创建的线程,可以重复使用来执行多个任务。
避免频繁的创建和销毁线程,从而减少了线程创建和销毁的开销,提高了系统的性能和效率。
异步编程默认使用线程池

什么是线程安全?

  1. 线程安全:多个线程共享资源时,对共享资源的访问不会导致数据不一致或不可预期的结果。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const int total = 100_000;

int count = 0;

var thread1 = new Thread(ThreadMethod);
var thread2 = new Thread(ThreadMethod);

thread1.Start();
thread2.Start();

thread1.Join();
thread2.Join();

Console.WriteLine($"Count: {count}");

void ThreadMethod()
{
for (int i = 0; i < total; i++)
{
count++;
}
}

结果:

1
2
3
PS D:\INFORMATION\dotnet\ConsoleApp> dotnet run 
Count: 114752
PS D:\INFORMATION\dotnet\ConsoleApp>

可以看到运行的结果不是200000,两个线程同时操作了count,这就是线程不安全。
2. 同步机制:用于协调和控制多个线程之间执行顺序和互斥访问共享资源,确保线程按照特性的顺序执行,避免竞态条件和数据不一致的问题。
3. 原子操作:执行过程中不会被中断的操作。不可分割,要么完全执行,要么完全不执行,没有中间状态。在多线程的情况下,原子操作能够保证数据的一致性和可靠性,避免出现竞态条件和数据竞争的问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const int total = 100_000;

int count = 0;

var thread1 = new Thread(ThreadMethod);
var thread2 = new Thread(ThreadMethod);

thread1.Start();
thread2.Start();

thread1.Join();
thread2.Join();

Console.WriteLine($"Count: {count}");

void ThreadMethod()
{
for (int i = 0; i < total; i++)
{
Interlocked.Increment(ref count);
// count++;
}
}

结果:

1
2
3
PS D:\INFORMATION\dotnet\ConsoleApp> dotnet run
Count: 200000
PS D:\INFORMATION\dotnet\ConsoleApp>

可以看出这里输出的结果是符合预期的,因为Interlocked提供了原子操作。

常用实现方式

  • 线程直接new
  • 线程池
  • 异步编程waite

线程Thread

  1. 线程创建
    创建Thead实例,并传入ThreadStart委托,还可以配置线程,如是否为后台线程
    调用Thread.Start方法,还可以传参
  2. 线程终止
    调用Tread.Join方法,等待线程的结束
    调用Thread.Interrupt方法,中断线程的执行
  3. 线程的挂起和恢复
    Thread.Suspend以及Thread.Resume
    比较新的.net版本这两个方法已经被标记为Obsolete,且调用会报错
    推荐使用锁,信号量等方式实现这一逻辑。

线程安全和同步机制Thread-Safety

  1. 原子操作
  2. 锁与信号量
  • lock & Monitor
  • Mutex
  • Semaphore
  • WaitHandle
  • ReaderWriterLock
  1. 轻量型
  • SemaphoreSlim
  • ManualResetEventSlim
  • ReaderWriteLockSlim
  1. 不要自己造轮子
  • 线程安全的单例:Lazy
  • 线程安全的集合类型:ConcurrentBag,ConcurrentStack,ConcurrentQueue,ConcurrentDictionary
  • 阻塞集合:BlockingCollection
  • 通道:Channel
  • 原子操作:interlocked
  • 周期任务:PeriodicTimer