在多线程下请注意代码的安全

当我们的程序在单一线程运行很正常,但是在多线程下,代码并不是哪么的强键!

我们编码的时候经常在使用缓存(或者使用设计模式的单件模式),缓存的东西一般是常用或者是运行代价非常昂贵的

 

下面我们看一个例子:

说明:yi.Components.YICache是一个管理缓存的Class

      yi.Components. ResourceManager是一个管理公共的资源的Class

 

yi.Components. ResourceManager下有以下这个方法获取资源信息(这在项目中可能是使用一个XML文件,或者是反序化一个流对象)

private static Hashtable GetResource()

      {

           String cacheKey = Type.GetType("ResourceManager").ToString();

           Hashtable resources = YICache.Get(cacheKey) as Hashtable;

 

           if (null == resources)

           {

              resources = new Hashtable();

             

              LoadResource(resources); //这里假设做一些非常昂贵的IO操作或者其它操作

              YICache.Max(cacheKey, resources);

           }

 

           return resources;

       }

以上哪一段码在单线程下运行的效果正是我们所想要的结果,哪么在多线程下是否是安全呢?

使用ACT对它进行测试一下,然后再使用监视工具进行监视,其结果并不是我们想要的,

测试的结果的是:平均运行两次就去执行非常昂贵的IO操作或者是其它操作

 

这时候你可以会想到,可能有ABC三个线程同时对GetResource()方法进行访问,哪么如果同时有ABC同时对LoadResource()这个方法进行操作.问题可已经找到了,哪么你可能认为上个锁不就完事.

 

然后将以上代码进行更改如下:

public static readonly object CacheObject = new object();

       private static Hashtable GetResource()

       {

           string cacheKey = Type.GetType("ResourceManager").ToString();

           Hashtable resources = YICache.Get(cacheKey) as Hashtable;

 

           if (null == resources)

           {

              lock (CacheObject)

              {

                  resources = new Hashtable();

                  LoadResource(resources);//这里假设做一些非常昂贵的IO操作或者其它操作

                  YICache.Max(cacheKey, resources);

              }

           }

 

           return resources;

       }

这代码看起来比第一次的好多了。

但是个假设有两个线程AB同时对GetResource()方法进行访问,哪么AB同时到达lock这一行代码,A先获取锁,然后B只有等待,而当A装载资源完成后,B仍然进行装载资源。

 

现在对以上代码再进行更改如下:

public static readonly object CacheObject = new object();

       private static Hashtable GetResource()

       {

           string cacheKey = Type.GetType("ResourceManager").ToString();

           Hashtable resources = YICache.Get(cacheKey) as Hashtable;

 

           if (null == resources)

           {

              lock (CacheObject)

              {

                  Hashtable resources = YICache.Get(cacheKey) as Hashtable;

                  if (null == resources)

                  {

                     resources = new Hashtable();

                     LoadResource(resources);//这里假设做一些非常昂贵的IO操作或者其它操作

                     YICache.Max(cacheKey, resources);

                  }

              }

           }

 

           return resources;

       }

这样就可以保证在多线程下对一些昂贵的操作进行比较好的控制。

 

以上的讨论在实现单件设计模式同样存在这个问题

关于锁的讨论:可以参考11月的MSDN杂志。具体名字忘记了。
原文地址:https://www.cnblogs.com/yi/p/679434.html