无关线程:线程之间没有任何联系,独立运行,互不干扰
相关线程:线程之间有联系,两个线程之间资源共享
临界线程:多个线程共享资源
临界区:访问临界资源代码
同步:两个线程协同工作才能完成同一项任务
相关线程实例:
public static char buffer;public static string str;static void Main(string[] args){// 开写线程Thread th = new Thread(write);th.Start();// 开度线程Thread re = new Thread(delegate() {for (int i = 0; i < str.Length; i++){char ch = buffer;Console.Write(ch); // 醒木非根,半风走一,谈疏君莫,是一说人人人人人人人人人人人人人Thread.Sleep(50);}});re.Start();Console.ReadLine();}/// <summary>/// 写入/// </summary>public static void write(){str = "醒木本非同根生,半生风雨走一程,谈笑疏狂君莫问,却是一位说书人";for (int i = 0; i < str.Length; i++){buffer = str[i];Thread.Sleep(30);}}
打印结果:
醒木非根,半风走一,谈疏君莫,是一说人人人人人人人人人人人人人
造成这种情况的原因是:读写线程时间不相同。
Interlocked(互锁):
使用线程锁Interlocked来解决这个问题
Interlocked的一些属性
Interlocked.Increment(ref value) 数值加一(原子性操作)
Interlocked.Decrement(ref value) 数值减一(原子性操作)
Interlocked.Exchange(ref value1, value2) 交换:把值2赋给值1;返回新值
Interlocked.CompareExchange(ref value1, value2, value3) 实现比较和交换两种功能:值1和值3比较,如果相同,把值2给值1,不相同则不作任何操作;返回原值(多用于判断条件)
Interlocked.Read读取计数器的值
Interlocked.Add使计数器增加指定的值
使用Interlocked改造完成之后的代码:
// 开写线程Thread th = new Thread(write);th.Start();// 开度线程Thread re = new Thread(delegate() {for (int i = 0; i < str.Length; i++){while (Interlocked.Read(ref num) == 0){Thread.Sleep(10);}char ch = buffer;Console.Write(ch); //Thread.Sleep(50);// 使值减少1Interlocked.Decrement(ref num);}});re.Start();Console.ReadLine();}/// <summary>/// 写入/// </summary>public static void write(){str = "醒木本非同根生,半生风雨走一程,谈笑疏狂君莫问,却是一位说书人";for (int i = 0; i < str.Length; i++){while (Interlocked.Read(ref num) == 1){Thread.Sleep(10);}buffer = str[i];//Thread.Sleep(30);// 使值增加1Interlocked.Increment(ref num);}}
Monitor(管程):
配合try-catch-finally(需要退出exit)或者Lock使用
锁定的对象应该声明为private static object obj = new object();尽量别用公共变量和字符串、this、值类型。
属性和方法:
Enter(Object) 在指定对象上获取排他锁。
Exit(Object) 释放指定对象上的排他锁。
IsEntered 确定当前线程是否保留指定对象锁。
Pulse 通知等待队列中的线程锁定对象状态的更改。
PulseAll 通知所有的等待线程对象状态的更改。
TryEnter(Object) 试图获取指定对象的排他锁。
TryEnter(Object, Boolean) 尝试获取指定对象上的排他锁,并自动设置一个值,指示是否得到了该锁。
Wait(Object) 释放对象上的锁并阻止当前线程,直到它重新获取该锁。
public static char buffer;public static string str;/// <summary>/// 此变量为InterLocked使用/// </summary>public static long num;/// <summary>/// 此变量为Monitor 使用/// </summary>public static object obj = new object();static void Main(string[] args){// 开写线程Thread th = new Thread(write);th.Start();// 开度线程Thread re = new Thread(delegate() {try{for (int i = 0; i < str.Length; i++){/*while (Interlocked.Read(ref num) == 0){Thread.Sleep(10);}//*/// 程序进入临界区,上锁Monitor.Enter(obj);char ch = buffer;Console.Write(ch); // 通知等待队列中的线程锁定对象状态的更改Monitor.Pulse(obj);// 释放对象上的锁并阻止当前线程,直到它重新获取该锁Monitor.Wait(obj);/*//Thread.Sleep(50);// 使值减少1Interlocked.Decrement(ref num);//*/}}catch (Exception){throw;}finally{Monitor.Exit(obj);}});re.Start();Console.ReadLine();}/// <summary>/// 写入/// </summary>public static void write(){try{str = "醒木本非同根生,半生风雨走一程,谈笑疏狂君莫问,却是一位说书人";for (int i = 0; i < str.Length; i++){/*while (Interlocked.Read(ref num) == 1){Thread.Sleep(10);}//*/// 程序进入临界区,上锁Monitor.Enter(obj);buffer = str[i];// 通知等待队列中的线程锁定对象状态的更改Monitor.Pulse(obj);// 释放对象上的锁并阻止当前线程,直到它重新获取该锁Monitor.Wait(obj);/*//Thread.Sleep(30);// 使值增加1Interlocked.Increment(ref num);//*/}}catch (Exception){throw;}finally {Monitor.Exit(obj);}}
Lock:上锁
Monitor和Lock的区别
1.Lock是Monitor的语法糖。
2.Lock只能针对引用类型加锁。
3.Monitor能够对值类型进行加锁,实质上是Monitor.Enter(object)时对值类型装箱。
4.Monitor还有其他的一些功能。
使用lock代替try之后:程序变得简洁了一些:仅限于Monitor
static void Main(string[] args){// 开写线程Thread th = new Thread(write);th.Start();// 开度线程Thread re = new Thread(delegate() {for (int i = 0; i < str.Length; i++){lock (obj){/*while (Interlocked.Read(ref num) == 0){Thread.Sleep(10);}//*/char ch = buffer;Console.Write(ch);// 通知等待队列中的线程锁定对象状态的更改Monitor.Pulse(obj);// 释放对象上的锁并阻止当前线程,直到它重新获取该锁Monitor.Wait(obj);/*//Thread.Sleep(50);// 使值减少1Interlocked.Decrement(ref num);//*/} }});re.Start();Console.ReadLine();}/// <summary>/// 写入/// </summary>public static void write(){str = "醒木本非同根生,半生风雨走一程,谈笑疏狂君莫问,却是一位说书人";for (int i = 0; i < str.Length; i++){lock(obj){/*while (Interlocked.Read(ref num) == 1){Thread.Sleep(10);}//*/buffer = str[i];// 通知等待队列中的线程锁定对象状态的更改Monitor.Pulse(obj);// 释放对象上的锁并阻止当前线程,直到它重新获取该锁Monitor.Wait(obj);/*//Thread.Sleep(30);// 使值增加1Interlocked.Increment(ref num);//*/}}}
以上方法对资源消耗比较大,合理使用
有好的建议,请在下方输入你的评论。