(转自伯乐在线)
一、相关概念(http://blog.jobbole.com/92458/)
不同的线程之间,代码区是共享的。因此可以执行相同的函数=>so,需要lock之类的东西,锁住。不然就乱套了。
缺点:
- 线程也是程序,所以线程需要占用内存,线程越多占用内存也越多;
- 多线程需要协调和管理,所以需要CPU时间跟踪线程;
- 线程之间对共享资源的访问会相互影响,必须解决竞用共享资源的问题;
- 线程太多会导致控制太复杂,最终可能造成很多Bug;
二、线程入口
Thread.Start之后,就开始执行一个委托:ThreadStart。
//ThreadTest.cs
using
System;
using
System.Threading;
namespace
ThreadTest
{
public
class
Alpha
{
public
void
Beta()
{
while
(
true
)
{
Console.WriteLine(
"Alpha.Beta is running in its own thread."
);
}
}
};
public
class
Simple
{
public
static
int
Main()
{
Console.WriteLine(
"Thread Start/Stop/Join Sample"
);
Alpha oAlpha =
new
Alpha();
//这里创建一个线程,使之执行Alpha类的Beta()方法
Thread oThread =
new
Thread(
new
ThreadStart(oAlpha.Beta));
oThread.Start();
while
(!oThread.IsAlive)
Thread.Sleep(1);
oThread.Abort();
oThread.Join();
Console.WriteLine();
Console.WriteLine(
"Alpha.Beta has finished"
);
try
{
Console.WriteLine(
"Try to restart the Alpha.Beta thread"
);
oThread.Start();
}
catch
(ThreadStateException)
{
Console.Write(
"ThreadStateException trying to restart Alpha.Beta. "
);
Console.WriteLine(
"Expected since aborted threads cannot be restarted."
);
Console.ReadLine();
}
return
0;
}
}
}
=>解析=================================================================
主函数进入之后,实例化一个alpha类。
开启一个新的线程(主线程之外的一个new one),指向alpha的beta方法。
线程开启。
=>但是这时并不一定程序就进入了beta里面。开启一个线程并不代表这个线程内的内容已经开始工作。因此让主线程sleep了1秒钟。主线程进入睡眠,这一秒确保了beta方法被启动。程序开始打印beta那句话。
线程终止。
join是在等待beta线程结束,主线程才能继续向下运行。
处理其他相关的异常。
======================================================================
相当于有两条线,CPU在这两条线之间切换工作。上面代码因为不能保证beta线程开始之后就抢到CPU资源,因此让主线程等待以确保CPU分给了beta线程。
三、LOCK,MONITOR,(http://blog.jobbole.com/92507/)
C#提供了一个关键字lock,它可以把一段代码定义为互斥段(critical section),互斥段在一个时刻内只允许一个线程进入执行,而其他线程必须等待。在C#中,关键字lock定义如下:
lock(expression) statement_block
expression代表你希望跟踪的对象,通常是对象引用。
- 如果你想保护一个类的实例,一般地,你可以使用this;
- 如果你想保护一个静态变量(如互斥代码段在一个静态方法内部),一般使用类名就可以了。
Monitor 类锁定一个对象
当多线程公用一个对象时,也会出现和公用代码类似的问题,这种问题就不应该使用lock关键字了,这里需要用到System.Threading中的一个类Monitor,我们可以称之为监视器,Monitor提供了使线程共享资源的方案。
Monitor类可以锁定一个对象,一个线程只有得到这把锁才可以对该对象进行操作。对象锁机制保证了在可能引起混乱的情况下一个时刻只有一个线程可以访问这个对象。
Monitor必须和一个具体的对象相关联,但是由于它是一个静态的类,所以不能使用它来定义对象,而且它的所有方法都是静态的,不能使用对象来引用。下面代码说明了使用Monitor锁定一个对象的情形:
1 2 3 4 |
|
如上所示,当一个线程调用Monitor.Enter()方法锁定一个对象时,这个对象就归它所有了,其它线程想要访问这个对象,只有等待它使用Monitor.Exit()方法释放锁。为了保证线程最终都能释放锁,你可以把Monitor.Exit()方法写在try-catch-finally结构中的finally代码块里。
对于任何一个被Monitor锁定的对象,内存中都保存着与它相关的一些信息:
- 其一是现在持有锁的线程的引用;
- 其二是一个预备队列,队列中保存了已经准备好获取锁的线程;
- 其三是一个等待队列,队列中保存着当前正在等待这个对象状态改变的队列的引用。
当拥有对象锁的线程准备释放锁时,它使用Monitor.Pulse()方法通知等待队列中的第一个线程,于是该线程被转移到预备队列中,当对象锁被释放时,在预备队列中的线程可以立即获得对象锁。
【未完。剩下的原文还没看懂。看懂了再写。】