在C#的多线程编程体系中,Thread类是最基础的原生线程操作类,位于System.Threading命名空间下,通过它可以手动创建和控制线程的生命周期,满足不同场景下的并发执行需求。
Thread类的基础使用:启动无参数线程
最简单的Thread类使用场景是启动一个不需要传递参数的线程,执行固定的任务逻辑。首先需要引入对应的命名空间,然后创建Thread实例,传入线程执行的方法,最后调用Start方法启动线程。
using System;
using System.Threading;
namespace ThreadDemo
{
class Program
{
static void Main(string[] args)
{
// 创建Thread实例,传入线程执行的方法
Thread thread = new Thread(PrintMessage);
// 启动线程
thread.Start();
// 主线程继续执行自己的逻辑
Console.WriteLine("主线程执行完毕");
}
static void PrintMessage()
{
Console.WriteLine("子线程正在执行任务");
}
}
}
给Thread线程传递参数
实际开发中经常需要给线程传递参数,Thread类支持两种常见的参数传递方式,分别是使用ParameterizedThreadStart委托和自定义类封装参数的方式。
方式一:使用ParameterizedThreadStart委托
这种方式要求线程执行的方法参数类型为object,启动线程时通过Start方法的参数传入对应的值,需要注意参数类型的转换。
using System;
using System.Threading;
namespace ThreadDemo
{
class Program
{
static void Main(string[] args)
{
Thread thread = new Thread(PrintWithParam);
// 传入参数,参数会被装箱为object类型
thread.Start("Hello Thread");
Console.WriteLine("主线程执行完毕");
}
static void PrintWithParam(object param)
{
// 需要将object类型转换为实际使用的类型
string message = param as string;
Console.WriteLine($"子线程接收到的参数:{message}");
}
}
}
方式二:自定义类封装参数
如果需要传递多个参数或者参数类型复杂,可以定义一个包含参数和执行逻辑的类,通过实例属性传递参数,这种方式不需要做类型转换,类型更安全。
using System;
using System.Threading;
namespace ThreadDemo
{
// 自定义封装参数和线程逻辑的类
class ThreadWorker
{
// 定义参数属性
public string Message { get; set; }
public int Count { get; set; }
// 定义线程执行的方法
public void DoWork()
{
for (int i = 0; i < Count; i++)
{
Console.WriteLine($"子线程执行:{Message},第{i + 1}次");
}
}
}
class Program
{
static void Main(string[] args)
{
ThreadWorker worker = new ThreadWorker
{
Message = "任务执行中",
Count = 3
};
// 创建Thread实例,传入实例的方法
Thread thread = new Thread(worker.DoWork);
thread.Start();
Console.WriteLine("主线程执行完毕");
}
}
}
控制线程的优先级和状态
Thread类提供了Priority属性来设置线程的优先级,优先级从低到高分为Lowest、BelowNormal、Normal、AboveNormal、Highest,默认优先级是Normal。同时可以通过ThreadState属性查看线程的当前状态,还可以通过Join方法让主线程等待子线程执行完毕再继续。
using System;
using System.Threading;
namespace ThreadDemo
{
class Program
{
static void Main(string[] args)
{
Thread thread = new Thread(PrintMessage);
// 设置线程优先级为最高
thread.Priority = ThreadPriority.Highest;
thread.Start();
// 主线程等待子线程执行完毕
thread.Join();
Console.WriteLine("子线程执行完毕,主线程继续");
}
static void PrintMessage()
{
Console.WriteLine("子线程正在执行任务");
Thread.Sleep(1000); // 模拟任务执行耗时
}
}
}
前台线程与后台线程
Thread类创建的线程默认是前台线程,前台线程会阻止进程退出,直到所有前台线程执行完毕,进程才会结束。如果设置IsBackground属性为true,线程会变为后台线程,当所有前台线程结束时,后台线程会自动终止,进程直接退出。
using System;
using System.Threading;
namespace ThreadDemo
{
class Program
{
static void Main(string[] args)
{
Thread foregroundThread = new Thread(PrintMessage);
// 默认是前台线程,不需要额外设置
foregroundThread.Start();
Thread backgroundThread = new Thread(PrintMessage);
// 设置为后台线程
backgroundThread.IsBackground = true;
backgroundThread.Start();
Console.WriteLine("主线程执行完毕,等待前台线程结束");
}
static void PrintMessage()
{
Thread.Sleep(2000);
Console.WriteLine("线程执行完毕");
}
}
}
Thread类的使用注意事项
- Thread类创建的是操作系统级别的线程,创建和销毁的代价比较高,不适合频繁创建大量线程的场景,这种场景建议使用线程池。
- 多线程访问共享资源时需要注意线程安全问题,可以通过lock关键字或者Monitor类来实现同步,避免数据错乱。
- 不要随意中断正在执行的线程,Thread.Abort方法已经过时,强行中断线程可能导致资源无法正确释放。