上一篇博客学习了如何简单的使用多线程。其实普通的多线程确实很简单,可是一个安全的高效的多线程却不那么简单。因此不少时候不正确的使用多线程反倒会影响程序的性能。html
下面先看一个例子 :安全
class Program { static int num = 1; static void Main(string[] args) { Stopwatch stopWatch = new Stopwatch(); //开始计时 stopWatch.Start(); ThreadStart threadStart = new ThreadStart(Run); for (int i = 0; i < 5; i++) { Thread thread = new Thread(threadStart); thread.Start(); } num++; Console.WriteLine("num is:" + num); Console.WriteLine("Main thread ID is:" + Thread.CurrentThread.ManagedThreadId.ToString()); //中止计时 stopWatch.Stop(); //输出执行的时间,毫秒数 Console.WriteLine("The execution time is " + stopWatch.ElapsedMilliseconds + " milliseconds."); Console.ReadKey(); } public static void Run() { num++; Console.WriteLine("num is:" + num); Console.WriteLine("Child thread ID is:" + Thread.CurrentThread.ManagedThreadId.ToString()); } }
执行结果:多线程
从上面能够看出变量 num 的值不是连续递增的,输出也是没有顺序的,并且每次输出的值都是不同的,这是由于异步线程同时访问一个成员时形成的,因此这样的多线程对于咱们来讲是不可控的。以上这个例子就是非线程安全的,那么要作到线程安全就须要用到线程同步。线程同步有不少种方法,好比以前用到过的 Join() 方法,它也能够实现线程的同步。下面咱们来试试:异步
class Program { static int num = 1; static void Main(string[] args) { Stopwatch stopWatch = new Stopwatch(); //开始计时 stopWatch.Start(); ThreadStart threadStart = new ThreadStart(Run); for (int i = 0; i < 5; i++) { Thread thread = new Thread(threadStart); thread.Start(); thread.Join(); } num++; Console.WriteLine("num is:" + num); Console.WriteLine("Main thread ID is:" + Thread.CurrentThread.ManagedThreadId.ToString()); //中止计时 stopWatch.Stop(); //输出执行的时间,毫秒数 Console.WriteLine("The execution time is " + stopWatch.ElapsedMilliseconds + " milliseconds."); Console.ReadKey(); } public static void Run() { num++; Console.WriteLine("num is:" + num); Console.WriteLine("Child thread ID is:" + Thread.CurrentThread.ManagedThreadId.ToString()); } }
执行结果:性能
这样就实现了简单的同步,相比起上面的代码也就只是添加了一行代码(thread.Join();),以前也提到了 Join() 这个方法用于阻止当前线程,直到前面的线程执行完成。但是这样虽然是实现了同步,可是却也阻塞了主线程的继续执行,这样和单线程貌似没什么区别了。既然这样咱们再去学习一下其余的方法。学习
实现线程同步还有一种锁的机制,下面是一种最简单的锁机制,即便用 lock。以下:spa
class Program { private object locker = new object(); int num = 1; static void Main(string[] args) { Program program = new Program(); Stopwatch stopWatch = new Stopwatch(); //开始计时 stopWatch.Start(); ThreadStart threadStart = new ThreadStart(program.Run); for (int i = 0; i < 5; i++) { Thread thread = new Thread(threadStart); thread.Start(); } program.num++; Console.WriteLine("num is:" + program.num); Console.WriteLine("Main thread ID is:" + Thread.CurrentThread.ManagedThreadId.ToString()); //中止计时 stopWatch.Stop(); //输出执行的时间,毫秒数 Console.WriteLine("The execution time is " + stopWatch.ElapsedMilliseconds + " milliseconds."); Console.ReadKey(); } public void Run() { lock (locker) { num++; Console.WriteLine("num is:" + num); Console.WriteLine("Child thread ID is:" + Thread.CurrentThread.ManagedThreadId.ToString()); } } }
执行结果:pwa
lock 是一种比较好用的简单的线程同步方式,它是经过为给定对象获取互斥锁来实现同步的。能够看到这种方式的确没有阻塞主线程,并且成员变量的值也是连续递增的,说明是线程安全的。lock 锁机制表示在同一时刻只有一个线程能够锁定同步对象(在这里是locker),任何竞争的的其它线程都将被阻止,直到这个锁被释放。线程
lock 的参数必须是基于引用类型的对象,不要是基本类型,好比 bool、int,这样根本不能同步,缘由是lock的参数要求是对象,若是传入 int,势必要发生装箱操做,这样每次lock的都将是一个新的不一样的对象。最好避免使用public类型或不受程序控制的对象实例,由于这样极可能致使死锁。永远也不要 lock 一个字符串。code
暂时先到这里,后面学了其余方法在继续更新。