zoukankan      html  css  js  c++  java
  • C#多线程编程之:集合类中Synchronized方法与SyncRoot属性原理分析

     我们知道,在.net的一些集合类型中,譬如Hashtable和ArrayList,都有Synchronized静态方法和SyncRoot属性,他们之间有联系吗?我怎么才能用好他们呢?
     以Hashtable为例,看看他们的基本用法:  

    1 Hashtable ht = Hashtable.Synchronized(new Hashtable());
    2  lock (ht.SyncRoot)
    3 {
    4 ......
    5 }

      Synchronized表示返回一个线程安全的Hashtable,什么样的 hashtable才是一个线程安全的呢?下边我们就从.NET的源码开始理解。

    复制代码
    1 public static Hashtable Synchronized(Hashtable table)
    2 {
    3 if (table == null)
    4 {
    5 throw new ArgumentNullException("table");
    6 }
    7 return new SyncHashtable(table);
    8 }
    复制代码

      从源码不难看出,Synchronized方法返回的其实是一个SynchHashtable类型的实例。在前边我们说过,Synchronized表示返回一个线程安全的Hashtable,从这个解释不难看出,SynchHashtable应该是继承自Hashtable。下边我们验证一下。看看 SynchHashtable类型的源码: 

    复制代码
    1 [Serializable]
    2 private class SyncHashtable : Hashtable
    3 {
    4 // Fields
    5 protected Hashtable _table;
    6
    7 // Methods
    8 internal SyncHashtable(Hashtable table)
    9 : base(false)
    10 {
    11 this._table = table;
    12 }
    13
    14 internal SyncHashtable(SerializationInfo info, StreamingContext context)
    15 : base(info, context)
    16 {
    17 this._table = (Hashtable)info.GetValue("ParentTable", typeof(Hashtable));
    18 if (this._table == null)
    19 {
    20 throw new SerializationException(Environment.GetResourceString("Serialization_InsufficientState"));
    21 }
    22 }
    23
    24 public override void Add(object key, object value)
    25 {
    26 lock (this._table.SyncRoot)
    27 {
    28 this._table.Add(key, value);
    29 }
    30 }
    31
    32 public override void Clear()
    33 {
    34 lock (this._table.SyncRoot)
    35 {
    36 this._table.Clear();
    37 }
    38 }
    39
    40 public override object Clone()
    41 {
    42 lock (this._table.SyncRoot)
    43 {
    44 return Hashtable.Synchronized((Hashtable)this._table.Clone());
    45 }
    46 }
    47
    48 public override bool Contains(object key)
    49 {
    50 return this._table.Contains(key);
    51 }
    52
    53 public override bool ContainsKey(object key)
    54 {
    55 return this._table.ContainsKey(key);
    56 }
    57
    58 public override bool ContainsValue(object key)
    59 {
    60 lock (this._table.SyncRoot)
    61 {
    62 return this._table.ContainsValue(key);
    63 }
    64 }
    65
    66 public override void CopyTo(Array array, int arrayIndex)
    67 {
    68 lock (this._table.SyncRoot)
    69 {
    70 this._table.CopyTo(array, arrayIndex);
    71 }
    72 }
    73
    74 public override IDictionaryEnumerator GetEnumerator()
    75 {
    76 return this._table.GetEnumerator();
    77 }
    78
    79 public override void GetObjectData(SerializationInfo info, StreamingContext context)
    80 {
    81 if (info == null)
    82 {
    83 throw new ArgumentNullException("info");
    84 }
    85 info.AddValue("ParentTable", this._table, typeof(Hashtable));
    86 }
    87
    88 public override void OnDeserialization(object sender)
    89 {
    90 }
    91
    92 public override void Remove(object key)
    93 {
    94 lock (this._table.SyncRoot)
    95 {
    96 this._table.Remove(key);
    97 }
    98 }
    99
    100 internal override KeyValuePairs[] ToKeyValuePairsArray()
    101 {
    102 return this._table.ToKeyValuePairsArray();
    103 }
    104
    105 // Properties
    106 public override int Count
    107 {
    108 get
    109 {
    110 return this._table.Count;
    111 }
    112 }
    113
    114 public override bool IsFixedSize
    115 {
    116 get
    117 {
    118 return this._table.IsFixedSize;
    119 }
    120 }
    121
    122 public override bool IsReadOnly
    123 {
    124 get
    125 {
    126 return this._table.IsReadOnly;
    127 }
    128 }
    129
    130 public override bool IsSynchronized
    131 {
    132 get
    133 {
    134 return true;
    135 }
    136 }
    137
    138 public override object this[object key]
    139 {
    140 get
    141 {
    142 return this._table[key];
    143 }
    144 set
    145 {
    146 lock (this._table.SyncRoot)
    147 {
    148 this._table[key] = value;
    149 }
    150 }
    151 }
    152
    153 public override ICollection Keys
    154 {
    155 get
    156 {
    157 lock (this._table.SyncRoot)
    158 {
    159 return this._table.Keys;
    160 }
    161 }
    162 }
    163
    164 public override object SyncRoot
    165 {
    166 get
    167 {
    168 return this._table.SyncRoot;
    169 }
    170 }
    171
    172 public override ICollection Values
    173 {
    174 get
    175 {
    176 lock (this._table.SyncRoot)
    177 {
    178 return this._table.Values;
    179 }
    180 }
    181 }
    182 }
    复制代码

      呵呵,果然不出我们所料,SyncHashtable果然继承自Hashtable,SyncHashtable之所有能实现线程的安全操作,就是因为在他们的一些方法中,就加了lock,我们知道,哪一个线程执行了lock操作,在他还没有释放lock之前,其他线程都要处于堵塞状态。 SyncHashtable就是通过这种方法,来实现所谓的线程安全。

      现在我们理解了Synchronized的含义和用法,那接下来我们看看他和SyncRoot之间的关系。
      SyncRoot表示获取可用于同步 Hashtable 访问的对象,老实说,这个解释不好理解,要想真正理解他的用法,我们还得从源码开始:

    复制代码
    1 public virtual object SyncRoot
    2 {
    3 get
    4 {
    5 if (this._syncRoot == null)
    6 {
    7 Interlocked.CompareExchange(ref this._syncRoot, new object(), null);
    8 }
    9 return this._syncRoot;
    10 }
    11 }
    复制代码

      如果您清楚Interlocked的用法,这段代码没什么难理解的了(不清楚的朋友找GOOGLE吧),Interlocked为多个线程共享的变量提供原子操作。原子操作就是单线程操作。在一个Hashtable实例中,不论我们在代码的任何位置调用SyncRoot,返回的都是同一个object类型的对象。我们在开始写的lock(ht.SyncRoot)和下边的操作作用是一样的:

    1 static object obj = new object();
    2 lock(obj)
    3 {
    4 ......
    5 }

      他们之间不同的是,我们声明的static object类型对象是类型级别的,而SyncRoot是对象级别的。

      通过上面的分析,我们都应该能理解Synchronized 和 SyncRoot用法,他们之间的关系就是:
      Hashtable 通过Synchronized方法,生成一个SynchHashtable类型的对象,在这个对象的一个方法中,通过lock (this._table.SyncRoot)这样的代码来实现线程安全的操作,其中this._table.SyncRoot返回的就是一个 object类型的对象,在一个SynchHashtable对象实例中,不管我们调用多少次,他是唯一的。

      另外,针对泛型集合的线程安全访问,由于泛型集合中没有直接公布SyncRoot属性,所以猛一看好似无从下手。

      但是查看集合泛型集合的源代码后就可发现他们实际上都提供了SyncRoot属性。

      以下以Queue<T>集合为例。 

    复制代码
    1 bool ICollection.IsSynchronized
    2 {
    3 get
    4 {
    5 return false;
    6 }
    7 }
    8
    9 object ICollection.SyncRoot
    10 {
    11 get
    12 {
    13 if (this._syncRoot == null)
    14 {
    15 Interlocked.CompareExchange(ref this._syncRoot, new object(), null);
    16 }
    17 return this._syncRoot;
    18 }
    19 }
    复制代码

      从以上源代码可以看出,这两个方法都被实现为了显式接口,所以必须将其显式转型为ICollection后才能使用。

    1 lock (((ICollection)_queue).SyncRoot)
    2 {
    3 int item = _queue.Dequeue();
    4 }

    本文来自CSDN博客,原文链接:http://blog.csdn.net/zztfj/archive/2010/06/01/5640889.aspx

  • 相关阅读:
    javascript package的一种简单"优雅"实现
    高效、快速、专业的外科手术团队
    贝塞尔曲线
    经典格斗游戏《街头霸王》的Javascript实现
    该死的痘痘
    同步/异步与阻塞/非阻塞的区别
    Shell echo用法
    凹凸Linux面试题
    VMware Workstation 9下安装Fedora 18教程(转)
    Linux中locale 详解(转)
  • 原文地址:https://www.cnblogs.com/1175429393wljblog/p/8078844.html
Copyright © 2011-2022 走看看