C# 线程--Thread类

目录

什么是线程?

Thread类的定义

创建和启动线程

[使用 ThreadStart 委托](#使用 ThreadStart 委托)

[使用 ParameterizedThreadStart 委托](#使用 ParameterizedThreadStart 委托)

Lambda简写

使用线程池(ThreadPool)

使用线程池的优点

[使用 ThreadPool 的一般步骤](#使用 ThreadPool 的一般步骤)

常用方法

Start()

Join()

[Sleep(int millisecondsTimeout)](#Sleep(int millisecondsTimeout))

Abort()

IsAlive

ManagedThreadId

SetApartmentState(ApartmentState)

Interrupt()


在C#中,线程(Thread)是执行代码的基本单位。一个程序可以包含多个线程,这些线程可以并行执行,从而提高效率和响应能力。

什么是线程?

线程是操作系统中执行代码的最小单位,它是进程(Process)内的一个独立执行流。每个线程都有自己的调用堆栈和程序计数器,但与同一进程内的其他线程共享内存和资源。使用线程可以实现多任务处理,提高程序的响应速度。

Thread类的定义

Thread 类位于 System.Threading 命名空间中。每个 Thread 对象表示一个线程,可以通过该对象启动、停止和管理线程的执行。

创建和启动线程

创建线程的一般步骤如下:

  1. 创建Thread对象:指定线程要执行的方法。
  2. 启动线程 :调用 Start() 方法。
  3. 可选:等待线程结束 :使用 Join() 方法。

需要创建一个线程。可以通过传递一个ThreadStartParameterizedThreadStart委托来指定线程要执行的方法。

使用 ThreadStart 委托

这是最常见的方式之一,适用于没有参数的方法。

cs 复制代码
using System;
using System.Threading;

class Program
{
    static void Main()
    {
        Thread thread = new Thread(PrintNumbers);
        thread.Start(); // 启动线程
        thread.Join();  // 等待线程完成
    }
    
    static void PrintNumbers()
    {
        for (int i = 0; i < 10; i++)
        {
            Console.WriteLine(i);
            Thread.Sleep(100);
        }
    }
}

使用 ParameterizedThreadStart 委托

如果你需要向线程传递参数,可以使用 ParameterizedThreadStart 委托:

cs 复制代码
Thread thread = new Thread(new ParameterizedThreadStart(ProcessData));
thread.Start(42); // 传递参数

static void ProcessData(object data)
{
    Console.WriteLine($"处理数据: {data}");
}

Lambda简写

以上是原理方法,平时我们可以直接用Lambda表达式来简写

推荐直接使用第三种,不用考虑那么多

cs 复制代码
// 创建线程,不传递参数----简写ThreadStart 委托
        Thread thread = new Thread(() => PrintNumbers());
        thread.Start(); // 启动线程
        thread.Join();  // 等待线程完成

// 创建一个线程,传递参数----简写ParameterizedThreadStart 委托
        Thread thread = new Thread(param => Compute((int)param));
        thread.Start(42); // 启动线程并传递参数42
        thread.Join();    // 等待线程完成

//直接用的匿名方法,方法内去调用compute,也相当于ThreadStart委托
Thread thread = new Thread(() => Compute(42)); // 直接传递参数42
thread.Start(); // 启动线程
thread.Join();  // 等待线程完成

使用线程池(ThreadPool)

线程池是一个可以重用的线程集合 ,允许程序在需要时获取线程,而不必每次都创建和销毁线程。这样可以提高性能与资源利用率,特别是在需要频繁启动和结束线程的场景中。

使用线程池的优点

  1. 性能提升:由于线程可以被重用,减少了线程创建和销毁的开销。
  2. 资源管理:线程池自动管理线程的数量,系统会根据需求动态调整线程池中的线程数量,以避免线程过多导致系统负担过重。
  3. 简化代码:通过线程池,可以避免手动管理线程的生命周期。

使用 ThreadPool 的一般步骤

  1. 使用 QueueUserWorkItem 方法提交工作项 :将要执行的任务定义为一个方法(通常是一个 Action)。
  2. 单独的工作线程将从线程池中获取该任务并执行:无需直接管理线程。
cs 复制代码
using System;
using System.Threading;

class Program
{
    static void Main()
    {
        Console.WriteLine("启动多个线程...");

        // 启动 5 个线程
        for (int i = 0; i < 5; i++)
        {
            int threadId = i; // 捕获循环变量
            ThreadPool.QueueUserWorkItem(DoWork, threadId);
        }

        // 等待用户输入以保持主线程运行
        Console.WriteLine("按任意键退出...");
        Console.ReadKey();
    }

    static void DoWork(object state)
    {
        int id = (int)state;
        Console.WriteLine($"线程 {id} 开始工作...");
        
        // 模拟工作负载
        for (int i = 0; i < 5; i++)
        {
            Console.WriteLine($"线程 {id} 正在处理任务 {i + 1}...");
            Thread.Sleep(new Random().Next(500, 1000)); // 随机休眠 500 到 1000 毫秒
        }
        
        Console.WriteLine($"线程 {id} 完成工作.");
    }
}
cs 复制代码
启动多个线程...
按任意键退出...
线程 0 开始工作...
线程 1 开始工作...
线程 2 开始工作...
线程 3 开始工作...
线程 4 开始工作...
线程 1 正在处理任务 1...
线程 0 正在处理任务 1...
线程 3 正在处理任务 1...
线程 2 正在处理任务 1...
线程 4 正在处理任务 1...
线程 1 正在处理任务 2...
线程 0 正在处理任务 2...
线程 1 完成工作.
线程 2 正在处理任务 2...
线程 3 正在处理任务 2...
线程 4 正在处理任务 2...
...
线程 4 完成工作.

常用方法

Start()

  • 描述: 启动线程,并执行与该线程关联的方法。
  • 用法 : 在创建 Thread 对象后,调用 Start() 方法来启动线程。

Join()

  • 阻塞主线程 :当主线程调用 thread.Join() 时,它会被阻塞,直到 thread 完成。也就是说,主线程不会继续执行后续的代码,直到这个线程的任务执行完毕。
  • 确保执行顺序 :使用 Join 方法的一个常见场景是,当你希望在所有子线程完成之前,确保主线程在做某些事情时,能够保证数据的一致性和正确性。例如,主线程可能需要处理子线程的结果,或者在所有任务完成后再进行下一个逻辑步骤。
cs 复制代码
using System;
using System.Threading;

class Program
{
    static void Main()
    {
        Thread thread1 = new Thread(() => Compute(1));
        Thread thread2 = new Thread(() => Compute(2));

        thread1.Start(); // 启动线程1
        thread2.Start(); // 启动线程2

        // 等待线程完成
        thread1.Join(); // 主线程在这里停下来,等待线程1完成
        thread2.Join(); // 然后等待线程2完成

        Console.WriteLine("所有任务已完成。");
    }

    static void Compute(int id)
    {
        Console.WriteLine($"任务{id}正在执行...");
        Thread.Sleep(2000); // 模拟一些工作
        Console.WriteLine($"任务{id}完成。");
    }
}
cs 复制代码
任务1正在执行...
任务2正在执行...
任务1完成。
任务2完成。
所有任务已完成。

Sleep(int millisecondsTimeout)

  • 描述: 使当前线程暂停执行指定的毫秒数。可以用于控制线程的执行频率。
  • 用法: 通常在执行任务过程中调用,以便适当地控制进程。

Abort()

  • 描述 : 强制终止线程的执行。需要注意的是,Abort 方法是一个被认为是不安全和不推荐使用的方法。
  • 用法: 由于可能导致资源泄漏和不确定的状态,建议使用其他机制(如标志或取消令牌)来停止线程。
cs 复制代码
using System;
using System.Threading;

class Program
{
    static void Main()
    {
        Thread thread = new Thread(() => {
            try
            {
                while (true) { /* 持续工作 */ }
            }
            catch (ThreadAbortException)
            {
                Console.WriteLine("线程被中止。");
            }
        });

        thread.Start();
        Thread.Sleep(1000); // 运行一段时间
        thread.Abort(); // 请求终止线程
        thread.Join(); // 等待线程完成
    }
}

//输出:  线程被中止。

IsAlive

  • 描述: 获取一个布尔值,指示线程是否仍在运行。可以用于在多线程环境中检查线程状态。
  • 用法: 用于判断线程是否处于活动状态。
cs 复制代码
class Program
{
    static void Main()
    {
        Thread thread = new Thread(() => {
            Thread.Sleep(2000); // 模拟长时间任务
        });

        thread.Start();
        Console.WriteLine("Is thread alive? " + thread.IsAlive); // 输出true
        thread.Join();
        Console.WriteLine("Is thread alive? " + thread.IsAlive); // 输出false
    }
}

ManagedThreadId

  • 描述: 获取当前线程的唯一标识符。这个ID可以用于跟踪和调试线程。
  • 用法: 在需要识别特定线程时,可以使用该属性。
cs 复制代码
using System;
using System.Threading;

class Program
{
    static void Main()
    {
        Thread thread = new Thread(() => {
            Console.WriteLine("当前线程的ManagedThreadId: " + Thread.CurrentThread.ManagedThreadId);
        });//当前线程的ManagedThreadId: 5(输出的ID可能会不同,因为它是在运行时生成的)

        thread.Start();
        thread.Join();
    }
}

SetApartmentState(ApartmentState)

  • 描述 : 设置线程的单元状态(Apartment State)。可以设置为 STA(单线程单元)或 MTA(多线程单元)这会影响COM组件的使用。
  • 用法 : 在调用 Start() 方法之前设置。

Interrupt()

  • 描述 : Interrupt() 方法用于中断一个正在等待、休眠或阻塞的线程。调用此方法时,如果目标线程处于阻塞状态(如调用 Thread.Sleep()Thread.Join()),该线程将抛出 ThreadInterruptedException 异常,并可以立即恢复执行。对于任何未阻塞状态下的线程,Interrupt() 方法不会产生影响。
  • 用法 : 如果一个线程正在休眠或等待,可以使用 Interrupt() 来唤醒它。
cs 复制代码
using System;
using System.Threading;

class Program
{
    static void Main()
    {
        // 创建一个线程,模拟一个长时间执行的操作
        Thread workerThread = new Thread(() =>
        {
            try
            {
                Console.WriteLine("线程正在休眠...");
                Thread.Sleep(10000); // 睡眠10秒
                Console.WriteLine("线程完成工作。");
            }
            catch (ThreadInterruptedException)
            {
                Console.WriteLine("线程被中断!");
            }
        });

        // 启动线程
        workerThread.Start();

        // 主线程等待一段时间后中断子线程
        Thread.Sleep(2000); // 等待2秒
        Console.WriteLine("请求中断线程...");
        workerThread.Interrupt(); // 中断线程

        // 等待子线程完成
        workerThread.Join();
        Console.WriteLine("主线程结束。");
    }
}
cs 复制代码
线程正在休眠...
请求中断线程...
线程被中断!
主线程结束。
相关推荐
两个人的幸福online3 分钟前
记录一次 用php 调用ai用stream返回
开发语言·php
漂流瓶66666630 分钟前
Scala的模式匹配变量类型
开发语言·后端·scala
夏天吃哈密瓜35 分钟前
Scala中的正则表达式01
大数据·开发语言·后端·正则表达式·scala
2401_8337880537 分钟前
Scala的模式匹配(2)
java·开发语言
Lbs_gemini060337 分钟前
C++研发笔记14——C语言程序设计初阶学习笔记12
c语言·开发语言·c++·笔记·学习
ac-er88881 小时前
GD库如何根据颜色生成纯色背景图
开发语言·php
悠悠龙龙2 小时前
框架模块说明 #05 权限管理_03
java·开发语言·spring
开心羊咩咩3 小时前
Idea 2024.3 突然出现点击run 运行没有反应,且没有任何提示。
java·ide·intellij-idea
waterme1onY3 小时前
IDEA中MAVEN的一些设置问题
java·maven·intellij-idea
阿华的代码王国3 小时前
【算法】——前缀和(矩阵区域和详解,文末附)
java·开发语言·算法·前缀和