Framework为我们提供了三个加锁的机制,分别是Monitor类、Lock关 键字和Mutex类。
总体而言,lock和monitor可以锁定对象,也可以锁定函数;而mutex一般用于锁定函数,并保证不同线程间同步调用函数,而不会受线程优先级影响。使用lock和monitor对象锁定对象时(即在对象外部锁定,或者在对象中的函数被调用的地方锁定对象),可以保证该对象一次只被一个线程所访问,但前提是:多个线程所锁定的对象必须是同一个对象,因此这种情况下应该定义一个全局的对象;锁定函数时,即在对象中的函数内部加锁,也可以保证该函数一次只被一个线程所访问,但前提也是各个线程访问的是同一个对象的该函数。而无论lock和monitor事锁定对象还是函数,都无法保证函数在不同线程间的同步,即函数不会被不同线程依次访问,而是优先级高的线程会一直霸占该对象或对象中的该函数,霸占一会儿,才会让给其他线程“霸占”;只有将lock和mutex一起使用,才能让函数的优先级失效,保证方法的同步。mutex对象一般在函数内部加锁,而不是在调用函数的地方。
综上所述,这三把锁的异同点如下:
(1)monitor一般在函数调用方加锁;mutex一般在函数内部加锁,即锁定被调用端;而lock则介于两者之间,调用方和被调用方通吃;
(2)使用monitor和lock给调用方加锁时,必须确保不同线程所访问的对象是同一对象,否则根本等于没锁;
(3)monitor和lock可以确保一次只有一个线程访问被锁定部分,但不保证同步;而mutex能够保证被锁定对象能够被不同线程同步访问。
下面通过几个例子来演示这三个对象之间的区别。
using System; using System.Collections.Generic; using System.Text; using System.Threading; namespace MonitorLockMutex { class Program { #region variable Thread thread1 = null; Thread thread2 = null; Mutex mutex = null; #endregion static void Main(string[] args) { Program p = new Program(); p.RunThread(); Console.ReadLine(); } public Program() { mutex = new Mutex(); thread1 = new Thread(new ThreadStart(thread1Func)); thread2 = new Thread(new ThreadStart(thread2Func)); } public void RunThread() { thread1.Start(); thread2.Start(); } private void thread1Func() { for (int count = 0; count < 10; count++) { TestFunc("Thread1 have run " + count.ToString() + " times"); Thread.Sleep(30); } } private void thread2Func() { for (int count = 0; count < 10; count++) { TestFunc("Thread2 have run " + count.ToString() + " times"); Thread.Sleep(100); } } private void TestFunc(string str) { Console.WriteLine("{0} {1}", str, System.DateTime.Now.Millisecond.ToString()); Thread.Sleep(50); } } } |
private void TestFunc(string str) { lock (this) { Console.WriteLine("{0} {1}", str, System.DateTime.Now.Millisecond.ToString()); Thread.Sleep(50); } } |
private void TestFunc(string str) { Monitor.Enter(this); Console.WriteLine("{0} {1}", str, System.DateTime.Now.Millisecond.ToString()); Thread.Sleep(50); Monitor.Exit(this); } |
private void thread1Func() { for (int count = 0; count < 10; count++) { mutex.WaitOne(); TestFunc("Thread1 have run " + count.ToString() + " times"); mutex.ReleaseMutex(); } } private void thread2Func() { for (int count = 0; count < 10; count++) { mutex.WaitOne(); TestFunc("Thread2 have run " + count.ToString() + " times"); mutex.ReleaseMutex(); } } private void TestFunc(string str) { Console.WriteLine("{0} {1}", str, System.DateTime.Now.Millisecond.ToString()); Thread.Sleep(50); } |
using System; using System.Threading; namespace ThreadLock } |
运行结果如下: