多线程学习-线程同步,lock初探
时间:2010-10-01 来源:伊羽
为了防止共享资源被多个线程破坏,就必须在代码中使用线程同步结构。
比如现在有一个计数器,每次访问都加1
public sealed class NormalCounter { Int32 num = 0; public void Add() { num++; } public Int32 GetNumber { get { return num; } } }
现在有3个不同的用户同时访问这个计数器(3个线程)
public class TestNormalCounter { public void StartWithMultiThread() { new Thread(() => { JustDoIt(); }).Start(); new Thread(() => { JustDoIt(); }).Start(); new Thread(() => { JustDoIt(); }).Start(); } void JustDoIt() { NormalCounter counter = new NormalCounter(); for (Int32 i = 0; i < 5; i++) { counter.Add(); Console.WriteLine(String.Concat("由ID是:", Thread.CurrentThread.ManagedThreadId, " 的线程输出当前值:", counter.GetNumber)); } } }
最后结果如下:
并没有达到计数器的效果,这是因为创建了3个实例,系统分配了3块内存分别进行了计数。
为了避免这种情况,就要线程同步结构。
public sealed class SingletonCounter { static SingletonCounter counter = null; static readonly Object thislock = new Object(); Int32 num = 0; SingletonCounter() { } public static SingletonCounter GetCounter { get { if (null == counter) { lock (thislock) { counter = new SingletonCounter(); } } return counter; } } public void Add() { num++; } public Int32 GetNumber { get { return num; } } }
//测试代码跟前一实例一样
这里用到了双检锁技巧来保证整个程序中,只有一个SingletonCounter实例,这样计数器便能正确的运行
(这里用到了单例设计模式,单例设计模式实际只需要用静态初始化,或者嵌套类延时初始化就可以简单的实现,这里只是演示如何使用lock来做同步)
结果如下:
lock 确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。
通常,应避免锁定 public 类型,否则实例将超出代码的控制范围。常见的结构 lock (this)、lock (typeof (MyType)) 和 lock ("myLock") 违反此准则:
如果实例可以被公共访问,将出现 lock (this) 问题。
如果 MyType 可以被公共访问,将出现 lock (typeof (MyType)) 问题。
由于进程中使用同一字符串的任何其他代码将共享同一个锁,所以出现 lock(“myLock”) 问题。
最佳做法是定义 private 对象来锁定, 或 private static 对象变量来保护所有实例所共有的数据。