目录
一、基本概念
二、基本用法
三、生命周期
四、线程的状态
五、线程的优先级
六、线程的前台与后台
七、常用的属性和方法
八、Sleep()、Join()、Interrupt()方法详解
1. Sleep 方法
2. Join 方法
3. Interrupt 方法
九、线程休眠
十、线程暂停与恢复
方法1:使用标志变量
方法2:使用 ManualResetEvent 或 AutoResetEvent
十一、线程取消
十二、线程安全与同步
十三、注意事项
Thread 类是 C# 中用于实现多线程编程的核心类之一,位于 System.Threading 命名空间下。通过 Thread 类,开发者可以创建和管理线程,从而实现并发执行任务的能力。
要使用 Thread 类,需要提供一个方法(或委托),该方法将在线程中运行。
using System;
using System.Threading;
class Program
{
static void Main(string[] args)
{
// 创建一个新的线程
Thread thread = new Thread(new ThreadStart(DoWork));
// 启动线程
thread.Start();
// 主线程继续执行
for (int i = 0; i < 5; i++)
{
Console.WriteLine("Main thread: " + i);
Thread.Sleep(500); // 模拟工作
}
// 等待子线程完成
thread.Join();
Console.WriteLine("Main thread finished.");
}
static void DoWork()
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine("Worker thread: " + i);
Thread.Sleep(500); // 模拟工作
}
}
}
输出示例:
Main thread: 0
Worker thread: 0
Main thread: 1
Worker thread: 1
Main thread: 2
Worker thread: 2
Main thread: 3
Worker thread: 3
Main thread: 4
Worker thread: 4
Main thread finished.
线程的生命周期包括以下几个阶段:
可以通过Thread.ThreadState属性获取线程的当前状态。例如:
Console.WriteLine(thread.ThreadState);
常见的状态值包括:
可以通过Thread.Priority属性设置线程的优先级。优先级的值包括:
thread.Priority = ThreadPriority.Highest;
线程可以分为前台线程和后台线程:
通过Thread.IsBackground属性设置线程为后台线程:
thread.IsBackground = true;
属性:
方法:
说明:
Thread.Suspend() 和 Thread.Resume(): 这两个方法已经被废弃。它们的主要问题是不可预测的行为,因为它们允许一个线程无条件地挂起另一个线程,而不考虑该线程当前的状态或它是否持有任何锁。这可能导致死锁或其他复杂的同步问题。如果需要暂停和恢复线程,应该寻找其他解决方案,比如使用更高层次的同步原语或者重新设计应用逻辑来避免这种需求。
Thread.Abort(): 虽然严格来说没有被完全废弃,但是它的使用也被强烈不推荐。调用 Thread.Abort() 可能导致线程在不安全的地方终止,可能会留下未释放的资源或者使程序处于不稳定状态。现代的做法倾向于通过协作的方式来停止线程,例如设置标志位让线程自行检查并退出。
详见后文“线程休眠”。
含义:Thread.Join 方法会阻塞调用线程,直到被调用的线程完成为止。这个方法对于等待子线程完成其工作非常有用,确保主线程或其它线程只有在所有必要的任务完成后才继续执行。
用法:
Thread thread = new Thread(new ThreadStart(SomeMethod));
thread.Start();
thread.Join(); // 主线程将在此处等待,直到thread线程完成
如果需要,你还可以指定一个超时时间,这样如果子线程在指定时间内没有完成,主线程也会继续执行:
bool didJoin = thread.Join(5000); // 等待最多5秒
if (didJoin)
{
Console.WriteLine("Thread completed.");
}
else
{
Console.WriteLine("Thread timed out.");
}
含义:Thread.Interrupt 方法用于中断处于等待状态(如通过调用 Sleep、Wait 或 Join 而进入等待状态)的线程。这会导致等待中的线程抛出 ThreadInterruptedException 异常。注意,如果你尝试中断一个未处于等待状态的线程,那么中断请求会被记住,并且当该线程最终进入等待状态时,它将立即抛出异常。
用法:
bool didJoin = thread.Join(5000); // 等待最多5秒
if (didJoin)
{
Console.WriteLine("Thread completed.");
}
else
{
Console.WriteLine("Thread timed out.");
}
在另一个线程中,你可以这样中断上述线程:
someThread.Interrupt(); // 中断someThread线程
使用 Interrupt 方法时要小心处理异常情况,并确保线程能够正确恢复或退出。
Thread.Sleep 方法使得当前正在执行的线程暂停执行指定的时间(以毫秒为单位)。在这段时间内,该线程不会占用CPU资源,但它的状态仍保留在内存中。
用法:
Thread.Sleep(1000); // 当前线程暂停1秒(1000毫秒)
这种方法通常用来简单地延迟线程的执行,或者给其他线程机会来执行(例如,在循环中定期调用,以避免独占CPU资源)。
通过共享的标志变量来控制线程的执行状态。这种方法简单且安全,因为线程会自行检查标志变量并决定是否暂停。
using System;
using System.Threading;
class Program
{
private static bool _isPaused = false; // 标志变量
private static readonly object _lock = new object(); // 锁对象,用于同步
static void Main()
{
Thread thread = new Thread(DoWork);
thread.Start();
Thread.Sleep(2000); // 主线程等待2秒
Console.WriteLine("暂停线程...");
PauseThread();
Thread.Sleep(3000); // 主线程等待3秒
Console.WriteLine("恢复线程...");
ResumeThread();
thread.Join(); // 等待工作线程完成(在这个例子中不会结束)
Console.WriteLine("主线程结束...");
}
static void DoWork()
{
while (true)
{
lock (_lock) // 使用锁保护对 _isPaused 的访问
{
if (_isPaused)
{
Console.WriteLine("线程已暂停...");
}
}
if (!_isPaused)
{
Console.WriteLine("线程正在运行...");
Thread.Sleep(500); // 模拟工作
}
else
{
Thread.Sleep(100); // 当线程暂停时减少CPU占用
}
}
}
static void PauseThread()
{
lock (_lock)
{
_isPaused = true; // 设置暂停标志
}
}
static void ResumeThread()
{
lock (_lock)
{
_isPaused = false; // 清除暂停标志
}
}
}
anualResetEvent 和 AutoResetEvent 是信号量机制,可以用来实现线程的暂停和恢复。它们提供了一种线程间通信的方式。
using System;
using System.Threading;
class Program
{
private static ManualResetEvent _pauseEvent = new ManualResetEvent(true); // 初始状态为未阻塞
static void Main()
{
Thread thread = new Thread(DoWork);
thread.Start();
Thread.Sleep(2000); // 主线程等待2秒
Console.WriteLine("暂停线程...");
_pauseEvent.Reset(); // 阻塞线程
Thread.Sleep(3000); // 主线程等待3秒
Console.WriteLine("恢复线程...");
_pauseEvent.Set(); // 唤醒线程
thread.Join(); // 等待线程完成
}
static void DoWork()
{
while (true)
{
_pauseEvent.WaitOne(); // 如果信号量未设置,则线程会阻塞在此处
Console.WriteLine("线程正在运行...");
Thread.Sleep(500); // 模拟工作
}
}
}
可以通过标志变量取消线程。
示例(使用标志变量):
using System;
using System.Threading;
class Program
{
private static bool _isRunning = true;
private static readonly object _lock = new object(); // 用于同步的锁对象
static void Main()
{
Thread thread = new Thread(DoWork);
thread.Start();
Thread.Sleep(2000); // 主线程等待2秒
lock (_lock) // 使用锁保护对 _isRunning 的写操作
{
_isRunning = false; // 停止线程
}
Console.WriteLine("主线程已通知线程停止...");
}
static void DoWork()
{
while (true)
{
bool shouldRun;
lock (_lock) // 使用锁保护对 _isRunning 的读操作
{
shouldRun = _isRunning;
}
if (!shouldRun)
{
Console.WriteLine("线程已停止...");
break;
}
Console.WriteLine("线程正在运行...");
Thread.Sleep(500); // 模拟工作
}
}
}
多线程环境下,多个线程可能同时访问共享资源,导致数据不一致或竞争条件。为了解决这些问题,可以使用以下同步机制:
示例:使用 lock 实现线程安全
using System;
using System.Threading;
class Program
{
private static object _lock = new object();
private static int _counter = 0;
static void Main(string[] args)
{
Thread t1 = new Thread(IncrementCounter);
Thread t2 = new Thread(IncrementCounter);
t1.Start();
t2.Start();
t1.Join();
t2.Join();
Console.WriteLine("Final Counter Value: " + _counter);
}
static void IncrementCounter()
{
for (int i = 0; i < 1000; i++)
{
lock (_lock)
{
_counter++;
}
}
}
}