上一篇介绍了如何开启线程,线程间相互传递参数,及线程中本地变量和全局共享变量区别。
本篇主要说明线程同步。
如果有多个线程同时访问共享数据的时候,就必须要用线程同步,防止共享数据被破坏。如果多个线程不会同时访问共享数据,可以不用线程同步。
线程同步也会有一些问题存在:
性能损耗。获取,释放锁,线程上下文建切换都是耗性能的。 同步会使线程排队等待执行。线程同步的几种方法:
阻塞
当线程调用Sleep,Join,EndInvoke,线程就处于阻塞状态(Sleep使调用线程阻塞,Join、EndInvoke使另外一个线程阻塞),会立即从cpu退出。(阻塞状态的线程不消耗cpu)
当线程在阻塞和非阻塞状态间切换时会消耗几毫秒时间。
//Join
static void Main()
{
Thread t = new Thread (Go);
Console.WriteLine ("Main方法已经运行....");
t.Start();
t.Join();//阻塞Main方法
Console.WriteLine ("Main方法解除阻塞,继续运行...");
}
static void Go()
{
Console.WriteLine ("在t线程上运行Go方法...");
}
//Sleep
static void Main()
{
Console.WriteLine ("Main方法已经运行....");
Thread.CurrentThread.Sleep(3000);//阻塞当前线程
Console.WriteLine ("Main方法解除阻塞,继续运行...");
}
//Task
static void Main()
{
Task Task1=Task.Run(() => {
Console.WriteLine("task方法执行...");
Thread.Sleep(1000);
});
Console.WriteLine(Task1.IsCompleted);
Task1.Wait();//阻塞主线程 ,等该Task1完成
Console.WriteLine(Task1.IsCompleted);
}
加锁(lock)
加锁使多个线程同一时间只有一个线程可以调用该方法,其他线程被阻塞。
同步对象的选择:
使用引用类型,值类型加锁时会装箱,产生一个新的对象。 使用private修饰,使用public时易产生死锁。(使用lock(this),lock(typeof(实例))时,该类也应该是private)。 string不能作为锁对象。 不能在lock中使用await关键字锁是否必须是静态类型?
如果被锁定的方法是静态的,那么这个锁必须是静态类型。这样就是在全局锁定了该方法,不管该类有多少个实例,都要排队执行。
如果被锁定的方法不是静态的,那么不能使用静态类型的锁,因为被锁定的方法是属于实例的,只要该实例调用锁定方法不产生损坏就可以,不同实例间是不需要锁的。这个锁只锁该实例的方法,而不是锁所有实例的方法.*
class ThreadSafe
{
private static object _locker = new object();
void Go()
{
lock (_locker)
{
......//共享数据的操作 (Static Method),使用静态锁确保所有实例排队执行
}
}
private object _locker2=new object();
void GoTo()
{
lock(_locker2)
//共享数据的操作,非静态方法,是用非静态锁,确保同一个实例的方法调用者排队执行
}
}










