无关线程:线程之间没有任何联系,独立运行,互不干扰
相关线程:线程之间有联系,两个线程之间资源共享
临界线程:多个线程共享资源
临界区:访问临界资源代码
同步:两个线程协同工作才能完成同一项任务
相关线程实例:
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);
// 使值减少1
Interlocked.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);
// 使值增加1
Interlocked.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);
// 使值减少1
Interlocked.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);
// 使值增加1
Interlocked.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);
// 使值减少1
Interlocked.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);
// 使值增加1
Interlocked.Increment(ref num);//*/
}
}
}
以上方法对资源消耗比较大,合理使用
有好的建议,请在下方输入你的评论。