【多线程-线程同步】
线程同步:协调多个线程间的并发操作,以获得符合预期的,确定的执行结果,消除多线程应用程序的不确定性.
使用线程的同步:可以保护资源同时只能由一个线程访问,一般采取的措施是获取锁,释放锁。即锁机制;可以协调线程的访问顺序,即某一资源只能先由线程A访问,再由线程B进行访问。
class Program
{
private static Thread subthread ;
private static int i;
static void Main(string[] args)
{
subthread = new Thread(new ThreadStart(GetShow));
subthread.Start(); //开启线程
GetShow();
//Console.WriteLine("{0}后台线程", Thread.CurrentThread.Name+Thread.CurrentThread.IsBackground+",结束");
}
static void GetShow()
{
Console.WriteLine(i);
i++;
//Console.WriteLine(i);
}
}
上面的代码执行时候,出现了两个线程同时访问同一个资源,向控制台输出后去执行i++操作,这样两个线程进来那一时间,i的值没有发生改变依旧是0,但执行i++后的值发生了改变,注释掉下面的输出运行程序发现:先输出2后输出的是1,这也是线程的执行顺序不确定而造成的值的输出顺序有差异。
使用排他锁,通过Monitor进行资源保护
1.使用对象作为锁对象:
class Program
{
private static Thread subthread ;
private static int i;
private static object obj = new object();
static void Main(string[] args)
{
Thread.CurrentThread.Name = "主";
subthread = new Thread(new ThreadStart(GetShow));
subthread.Name = "subject";
subthread.Start(); //开启线程
GetShow();
//Console.WriteLine("{0}后台线程", Thread.CurrentThread.Name+Thread.CurrentThread.IsBackground+",结束");
}
static void GetShow()
{
Monitor.Enter(obj);// 在指定对象上获取排他锁。
Console.WriteLine(Thread.CurrentThread.Name+">>"+i);
i++;
Console.WriteLine(Thread.CurrentThread.Name+">>"+i);
Monitor.Exit(obj); // 释放指定对象上的排他锁。
}
}
使用System.Type进行锁对象:
修改上面的方法:运行结果与上面一致。
<span style="white-space:pre"> </span>static void GetShow()
{
Monitor.Enter(typeof(Program));// 在指定对象上获取排他锁。
Console.WriteLine(Thread.CurrentThread.Name+">>"+i);
i++;
Console.WriteLine(Thread.CurrentThread.Name+">>"+i);
Monitor.Exit(typeof(Program)); // 释放指定对象上的排他锁。
}
使用lock加锁:
如果上面的Monitor.Exit(typeof(Program))前面代码出现异常的话,主线程在执行到异常出会抛出异常,可以通过:try catch finall进行处理:
try
{
Console.WriteLine(Thread.CurrentThread.Name + ">>" + i);
i++;
Console.WriteLine(Thread.CurrentThread.Name + ">>" + i);
throw new Exception("asdasd");
}
catch
{
}
finally
{
Monitor.Exit(typeof(Program)); // 释放指定对象上的排他锁。
}
使用lock可以进行简化:实现效果和上面一样.
lock (typeof(Program))
{
try
{
Console.WriteLine(Thread.CurrentThread.Name + ">>" + i);
i++;
Console.WriteLine(Thread.CurrentThread.Name + ">>" + i);
throw new Exception("asdasd");
}
catch { }
}
进行[MethodImpl(MethodImplOptions.Synchronized)]标记
创建线程的安全类型,可以使用[MethodImpl(MethodImplOptions.Synchronized)]进行标记:
[MethodImpl(MethodImplOptions.Synchronized)]//进行标记
static void GetShow()
{
try
{
Console.WriteLine(Thread.CurrentThread.Name + ">>" + i);
i++;
Console.WriteLine(Thread.CurrentThread.Name + ">>" + i);
throw new Exception("asdasd");
}
catch { }
}
使用Monitor协调线程的执行顺序:
class Program
{
private static Thread subthread ;
static void Main(string[] args)
{
Program p=new Program ();
Thread.CurrentThread.Name = "主线程";
subthread = new Thread(new ThreadStart(p.GetShow));
subthread.Name = "子线程";
subthread.Start(); //开启线程
lock (typeof(Program))
{
Monitor.Wait(typeof(Program)); // 释放对象上的锁并阻止当前线程,直到它重新获取该锁。
Console.WriteLine(Thread.CurrentThread.Name + "开始执行其他逻辑");
}
}
void GetShow()
{
lock (typeof(Program))
{
Console.WriteLine(subthread.Name+"线程执行完毕");
Monitor.Pulse(typeof(Program)); //通知等待队列中的线程锁定对象状态的更改。
}
}
}
还没有评论,来说两句吧...