线程的同步有多种方法,这里简单学习一下使用monitor这个对象同步线程。
我们知道如果程序中有些操作比较耗时,那么就可以指派专门的线程来处理这件事,有时候,启动的多个线程需要同时执行一个方法、修改同一个变量等,那么这时候如何做好线程同步,就很关键。
程序实现的效果是:
两个线程删除同一个数组中的数据,删除完成后自动关闭线程。使用monitor对象实现。
程序实现的主要思路:
1、定义一个共同执行的方法——Run执行删除数组的元素,在这个方法中使用monitor对象同步线程。
如果有一个线程正在执行该方法,那么就将该方法保持一个种锁定的方法,其他的线程就只能等待,很多说法把monitor对象比作是一个出租车,如果有人已经打了这辆车,那么其他的人就不能再上,只能等待里面的人下车后才有机会上车。
/// <summary>
/// 共同执行的删除数组的元素的方法
/// </summary>
public void Run()
{
//记录要删除的数据
string stringValue = null;
#region 使用monitor对象同步线程
//***********************************使用monitor对象同步线程*********************************************//
//如果已经被某个线程锁定
//使用线程锁住
while (true)
{
Monitor.Enter(this);
stringValue = (string)stringList[0];
Console.WriteLine(Thread.CurrentThread.Name+"删除了"+stringValue );
stringList.RemoveAt(0);
//如果数组中的所有元素都已经被删除,那么就自动关闭线程
if (stringList.Count==0)
{
//执行关闭线程的事件,调用委托的方法
OnNumberClear(this, new EventArgs());
}
Monitor.Exit(this );
Thread.Sleep(5);
}
//***********************************使用monitor对象同步线程*********************************************//
#endregion
}
//数据删除完成后引发的事件(事件也是一种委托)
private event EventHandler OnNumberClear;
//关闭线程的方法,要委托给自定义的事件
/// <summary>
/// 执行完成之后,停止所有线程
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void ThreadDemo_OnNumberClear(object sender,EventArgs e )
{
Console.WriteLine("执行完成,停止所有线程。");
thredOne.Abort();
threadTwo.Abort();
}
3、 在类的构造函数中初始化两个线程、要删除的数组、指定要执行的方法和委托给自定义事件的方法。
/// <summary>
/// 类的构造函数中将线程和数组对象以及完成后要执行的委托方法都构造好
/// </summary>
/// <param name="number">生成数组的元素个数</param>
public ThreadDemo(int number)
{
//生成字串数组
Random random = new Random(1000000);
stringList = new ArrayList(number);
for (int n = 0; n < number; n++)
{
stringList.Add(random.Next().ToString());
}
//初始化线程,指明相应的线程要做什么
thredOne = new Thread( new ThreadStart(Run));
threadTwo = new Thread(new ThreadStart(Run));
//给线程起名字
thredOne.Name = "线程1";
threadTwo.Name = "线程2";
//将关闭线程的方法委托给自定的事件
//数据删除完成后,引发OnNumberClear事件;该事件将触发ThreadDemo_OnNumberClear方法执行
//将ThreadDemo_OnNumberClear方法委托到OnNumberClear事件中去执行
OnNumberClear += new EventHandler(ThreadDemo_OnNumberClear);
}
4、其他的部分就不做解释,下面是所有的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Collections;
namespace DelArrayThreadExcise
{
//这个程序的思路是共同做一件事情(从一个ArrayList中删除元素),如果执行完成了,两个线程都停止执行。
//所有的工作都在一个类中实现
//******************************实现两个线程删除一个数组中的元素********************************************
//构造函数中:定义两个线程;生成数组
//共同执行的删除的方法
//定义一个启动多线程的方法
//如果所有的数据都删除后就,自动终止线程,使用委托实现
class ThreadDemo
{
//定义线程和数组对象
private Thread thredOne;
private Thread threadTwo;
private ArrayList stringList;
//数据删除完成后引发的事件(事件也是一种委托)
private event EventHandler OnNumberClear;
/// <summary>
/// 类的构造函数中将线程和数组对象以及完成后要执行的委托方法都构造好
/// </summary>
/// <param name="number">生成数组的元素个数</param>
public ThreadDemo(int number)
{
//生成字串数组
Random random = new Random(1000000);
stringList = new ArrayList(number);
for (int n = 0; n < number; n++)
{
stringList.Add(random.Next().ToString());
}
//初始化线程,指明相应的线程要做什么
thredOne = new Thread( new ThreadStart(Run));
threadTwo = new Thread(new ThreadStart(Run));
//给线程起名字
thredOne.Name = "线程1";
threadTwo.Name = "线程2";
//将关闭线程的方法委托给自定的事件
//数据删除完成后,引发OnNumberClear事件;该事件将触发ThreadDemo_OnNumberClear方法执行
//将ThreadDemo_OnNumberClear方法委托到OnNumberClear事件中去执行
OnNumberClear += new EventHandler(ThreadDemo_OnNumberClear);
}
/// <summary>
/// 共同执行的删除数组的元素的方法
/// </summary>
public void Run()
{
//记录要删除的数据
string stringValue = null;
#region 使用monitor对象同步线程
//***********************************使用monitor对象同步线程*********************************************//
//如果已经被某个线程锁定
//使用线程锁住
while (true)
{
Monitor.Enter(this);
stringValue = (string)stringList[0];
Console.WriteLine(Thread.CurrentThread.Name+"删除了"+stringValue );
stringList.RemoveAt(0);
//如果数组中的所有元素都已经被删除,那么就自动关闭线程
if (stringList.Count==0)
{
//执行关闭线程的事件,调用委托的方法
OnNumberClear(this, new EventArgs());
}
Monitor.Exit(this );
Thread.Sleep(5);
}
//***********************************使用monitor对象同步线程*********************************************//
#endregion
}
//开启线程的方法
public void Action()
{
thredOne.Start();
threadTwo.Start();
}
//关闭线程的方法,要委托给自定义的事件
/// <summary>
/// 执行完成之后,停止所有线程
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void ThreadDemo_OnNumberClear(object sender,EventArgs e )
{
Console.WriteLine("执行完成,停止所有线程。");
thredOne.Abort();
threadTwo.Abort();
}
static void Main(string[] args)
{
ThreadDemo demo = new ThreadDemo(1000);
demo.Action();
}
}
}
5、总结:
1.上面使用了monitor对象同步线程,当一个线程使用monitor对象的Enter方法执行某段代码后,Exit方法前,其他的线程就没有机会在这个时刻,执行这些代码。
2.自定义事件也是一种委托,对事件的声名其实就是声明一个私有的委托变量。