实战(代码)练习 C# 多线程
2011-12-22 17:15 音乐让我说 阅读(555) 评论(0) 编辑 收藏 举报所有说明在代码中。
public class MessageReceivedEventArgs : EventArgs
{
public string Message
{
get;
set;
}
public MessageReceivedEventArgs(string message)
{
this.Message = message;
}
}
上面定义了一个继承自 EventArgs 的类,用来做事件的参数。
public class UnsafeMessenger
{
/// <summary>
/// 当信息发送后触发
/// </summary>
public event EventHandler<MessageReceivedEventArgs> OnMessageReceived;
public void SendMessage(object message)
{
if(!(message is string))
{
throw new ArgumentException("必须传入 String 类型的消息");
}
SendMessage((string)message);
}
/// <summary>
/// 发送信息
/// </summary>
/// <param name="message"></param>
public void SendMessage(string message)
{
Thread.Sleep(2000); // 模拟一个耗时的发送消息的过程
Console.WriteLine("==========消息发送成功!==========");
var target = OnMessageReceived;
// 你可能好奇:为什么要用一个变量来接收一下。解释如下:
// 因为在多线程中,客户端既然可以订阅事件,也可以取消订阅。
// 那如果客户端刚开始订阅了,后来又取消了,就容易发生异常。
// 比如:
// if(OnMessageReceived != null)
// {
// OnMessageReceived(this, new MessageReceivedEventArgs(message));
// }
// 上面的代码就很可能发生空指针异常,在多线程环境下。
// 总的原因就是:委托的不可变性,就像 string 一样。
// 当委托在 Add 或 Remove 后,就会形成一个新的委托。
if (target != null)
{
Thread.Sleep(4000);
target(this, new MessageReceivedEventArgs(message));
}
}
}
上面我们定义了一个 UnsafeMessenger 类用来发送消息,那为什么要加一个事件呢,因为客户端可能需要在发送完消息后,再做一些其他的事。
class Program
{
static void Main(string[] args)
{
string objMessage = "你们好,欢迎来到 .NET 的世界!";
UnsafeMessenger unsafeMsg = new UnsafeMessenger();
unsafeMsg.OnMessageReceived += new EventHandler<MessageReceivedEventArgs>(OnMessageReceived1);
unsafeMsg.OnMessageReceived += new EventHandler<MessageReceivedEventArgs>(OnMessageReceived2);
Thread childThread = new Thread(unsafeMsg.SendMessage);
childThread.Name = "运行发送消息的子线程";
childThread.IsBackground = false; // 不用设置也可以,默认为 false
// 什么是后台线程,我的理解是:
// 后台线程就是在后台运行的线程,主线程不会等待子线程执行完毕。
Console.WriteLine("当前子线程的状态:" + childThread.ThreadState);
Console.WriteLine("当前子线程是否属于托管线程池:" + childThread.IsThreadPoolThread);
childThread.Start(objMessage);
Thread.Sleep(3000);
unsafeMsg.OnMessageReceived -= new EventHandler<MessageReceivedEventArgs>(OnMessageReceived1);
unsafeMsg.OnMessageReceived -= new EventHandler<MessageReceivedEventArgs>(OnMessageReceived2);
Console.WriteLine("主线程运行完毕!");
}
static void OnMessageReceived1(object sender, MessageReceivedEventArgs e)
{
Thread.Sleep(3000); // 假设耗时 3 秒钟
Console.WriteLine("\n\n");
Console.WriteLine("当前线程的名称:" + Thread.CurrentThread.Name);
Console.WriteLine("消息发送成功后,调用了本回调函数(OnMessageReceived1)。消息:" + e.Message + "\n");
}
static void OnMessageReceived2(object sender, MessageReceivedEventArgs e)
{
Thread.Sleep(5000); // 假设耗时 5 秒钟
Console.WriteLine("\n\n");
Console.WriteLine("当前线程的名称:" + Thread.CurrentThread.Name);
Console.WriteLine("消息发送成功后,调用了本回调函数(OnMessageReceived2)。消息:" + e.Message + "\n");
}
}
运行结果截图:
PS:发一张 CSDN 数据库泄露后,我的查询结果的图。
谢谢浏览!
作者:音乐让我说(音乐让我说 - 博客园)
出处:http://music.cnblogs.com/
文章版权归本人所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。