目录
1、线程的挂起、恢复
static void methodA()
{
//method body...
}
[Obsolete]
public static void Main()
{
System.Threading.Thread thread = new System.Threading.Thread(methodA);
thread.Start(); //启动线程
thread.Suspend();//挂起线程,或者如果线程已挂起,则不起作用。
thread.Resume(); //继续已挂起的线程。该线程尚未启动、 已死或未处于挂起状态就会异常
}
2、线程的启动与终止
static void methodA()
{
}
[Obsolete]
public static void Main()
{
System.Threading.Thread thread = new System.Threading.Thread(methodA);
thread.Start();
if (thread.IsAlive)
{
thread.Abort();//终止线程。(终止已经挂起的线程会发送异常)
thread.Join();//阻止调用线程,直到由该实例表示的线程终止
}
}
3、注意事项
(1)Suspend()与Abort()方法不一定立即起作用。
对于Suspend(),.net允许要挂起的线程再执行几个指令,目的时为了达到.net认为线程可以安全挂起的状态(是为了确保垃圾收集器执行正确的操作)。
Abort()中止线程,会在受影响的线程中产生一个ThreadAbortException异常,以这种方式中止线程。 如果线程当前执行try块中的代码,则在线程正在中止前,将执行相应的finally块。这样就可以保证清理资源,并有机会确保线程正在处理的数据处于有效状态。
.net使用的异常机制使线程中的中止更加安全,但中止需要一定的时间(理论上,异常块中处理的代码执行多长时间是没有限制的)。因此,在中止线程后需要等待一段时间,线程完全中止后,才能继续执行其他操作。
若后续的处理依赖于该中止的线程,可使用Join()方法,等待线程中止。
(2)Join()
thread.Abort();//终止线程。(终止已经挂起的线程会发送异常)
thread.Join();//阻止调用线程,直到由该实例表示的线程终止
Join()的其他重载方法可以指定等待的时间期限。
若过了等待时间期限,调用代码会继续执行;
若没有指定时间期限,线程就要等待需要等待的时间。
4、线程的状态及优先级
Thread.ThreadState,代表线程运行的状态。
ThreadPriority,代表线程的优先级
5、线程间通信
(1)关键字lock
lock可以将一段代码定义为互斥段。互斥段在一个时刻只允许一个线程进入执行,而其他线程必须等待。
避免lock public类型或lock不受应用程序控制的对象实例。
lock (expression)
{
//互斥代码片段。在一个时刻只能被一个线程执行
}
expression代表希望跟踪的对象,通常是对象引用。
通常保护一个类的实例,可以使用this;
保护一个静态变量,使用类名就可以了。
(2)线程监视器
多线程公用一个对象时,可使用System.Threading.Monitor类
System.Threading.Monitor提供了是线程共享资源的方案。
System.Threading.Monitor可以锁定一个对象,一个线程只有得到这把锁才能对给对象进行操作。一个时刻只有一个线程可以访问这个对象。
System.Threading.Monitor必须和一个具体的对象关联。
Queue<string> queue = new Queue<string>(); //新建对象
System.Threading.Monitor.Enter(queue);//锁定对象
try
{
//在这里操作queue对象
}
catch (Exception ex)
{
throw;
}
finally
{
System.Threading.Monitor.Exit(queue);//释放对象的排它锁
}
lock就是用System.Threading.Monitor实现的,lock等效于try-finally语句块。
使用lock比直接使用System.Threading.Monitor更可靠,一方面是因为lock简洁,另一方面是因为lock确保了即使受保护的代码发生异常,也可以释放基础监视器。
(3)线程间通信
互斥:当有多个线程访问共享资源而不使资源被破坏;
同步:当一个线程需要将某个任务已经完成的情况通知另外一个或多个线程;
Queue<string> queue = new Queue<string>(); //新建对象
System.Threading.Monitor.Enter(queue);//锁定对象
try
{
//在这里操作queue对象
System.Threading.Monitor.Pulse(this);//通知等待队列中的线程锁定对象状态的更改。(参数: obj: 线程正在等待的对象。)
System.Threading.Monitor.PulseAll(this);//通知所有的等待线程对象状态的更改。(参数: obj: 发送脉冲的对象。)
}
catch (Exception ex)
{
throw;
}
finally
{
System.Threading.Monitor.Exit(queue);//释放对象的排它锁
}
(4)子线程访问主线程的控件
不同的线程在不同的内存空间中各自无干扰地运行着。在不做任何处理的情况下,若子线程访问有主线程创建的控件时,会报错。
6、线程池和定时器
(1)线程池
(2)定时器
7、互斥对象
System.Threading.Mutex,是一个同步基元。
线程使用Muxtex.WaitOne()方法等待System.Threading.Mutex对象被释放,一旦System.Threading.Mutex对象被释放,他就自动拥有这个对象,直到他调用System.Threading.Mutex.ReleaseMutex()方法释放这个对象。而在此此期间,其他想要获取这个System.Threading.Mutex对象的线程只能等待。
说明:尽管System.Threading.Mutex可以用于进程内的线程同步,但是通常使用Monitor。
因为监视器Monitor是专门为.net framework而设计的,因而Monitor可以更好地利用资源。
Mutex类是Window32构造的包装,虽然Mutex功能比Monitor更强大,但Mutex需要的互操作转换更消耗计算资源。