Monitor 类锁定一个对象
当多线程公用一个对象时也会出现和公用代码类似的问题这种问题就不应该使用lock关键字了这里需要用到SystemThreading中的一个类Monitor我们可以称之为监视器Monitor提供了使线程共享资源的方案
Monitor类可以锁定一个对象一个线程只有得到这把锁才可以对该对象进行操作对象锁机制保证了在可能引起混乱的情况下一个时刻只有一个线程可以访问这个对象
Monitor必须和一个具体的对象相关联但是由于它是一个静态的类所以不能使用它来定义对象而且它的所有方法都是静态的不能使用对象来引用下面代码说明了使用Monitor锁定一个对象的情形
……
Queue oQueue=new Queue()……
MonitorEnter(oQueue)……//现在oQueue对象只能被当前线程操纵了MonitorExit(oQueue)//释放锁
如上所示当一个线程调用MonitorEnter()方法锁定一个对象时这个对象就归它所有了其它线程想要访问这个对象只有等待它使用 MonitorExit()方法释放锁为了保证线程最终都能释放锁你可以把MonitorExit()方法写在trycatch finally结构中的finally代码块里
对于任何一个被Monitor锁定的对象内存中都保存着与它相关的一些信息其一是现在持有锁的线程的引用其二是一个预备队列队列中保存了已经准备好获取锁的线程其三是一个等待队列队列中保存着当前正在等待这个对象状态改变的队列的引用
当拥有对象锁的线程准备释放锁时它使用MonitorPulse()方法通知等待队列中的第一个线程于是该线程被转移到预备队列中当对象锁被释放时在预备队列中的线程可以立即获得对象锁
下面是一个展示如何使用lock关键字和Monitor类来实现线程的同步和通讯的例子也是一个典型的生产者与消费者问题
这个例程中生产者线程和消费者线程是交替进行的生产者写入一个数消费者立即读取并且显示(注释中介绍了该程序的精要所在)
用到的系统命名空间如下using Systemusing SystemThreading
首先定义一个被操作的对象的类Cell在这个类里有两个方法ReadFromCell()和WriteToCell消费者线程将调用 ReadFromCell()读取cellContents的内容并且显示出来生产者进程将调用WriteToCell()方法向 cellContents写入数据
示例如下
public class Cell
{
int cellContents; // Cell对象里边的内容
bool readerFlag = false; // 状态标志为true时可以读取为false则正在写入
public int ReadFromCell( )
{
lock(this) // Lock关键字保证了什么请大家看前面对lock的介绍
{
if (!readerFlag)//如果现在不可读取
{
try
{
//等待WriteToCell方法中调用MonitorPulse()方法
MonitorWait(this);
}
catch (SynchronizationLockException e)
{
ConsoleWriteLine(e);
}
catch (ThreadInterruptedException e)
{
ConsoleWriteLine(e);
}
}
ConsoleWriteLine(Consume: {}cellContents);
readerFlag = false;
//重置readerFlag标志表示消费行为已经完成
MonitorPulse(this);
//通知WriteToCell()方法(该方法在另外一个线程中执行等待中)
}
return cellContents;
}
public void WriteToCell(int n)
{
lock(this)
{
if (readerFlag)
{
try
{
MonitorWait(this);
}
catch (SynchronizationLockException e)
{
//当同步方法(指Monitor类除Enter之外的方法)在非同步的代码区被调用
ConsoleWriteLine(e);
}
catch (ThreadInterruptedException e)
{
//当线程在等待状态的时候中止
ConsoleWriteLine(e);
}
}
cellContents = n;
ConsoleWriteLine(Produce: {}cellContents);
readerFlag = true;
MonitorPulse(this);
//通知另外一个线程中正在等待的ReadFromCell()方法
}
}
}