C# Synchronized 和 SyncRoot 实现线程同步的源码分析及泛型集合的线程安全访问
转载:http://blog.csdn.net/zztfj/article/details/5640889
Synchronized vs SyncRoot 我们知道,在.net的一些集合类型中,譬如Hashtable和ArrayList,都有Synchronized静态方法和SyncRoot实例方法,他们之间有联系吗?我怎么才能用好他们呢?
我们以Hashtable为例,看看他们的基本用法:
Hashtable ht = Hashtable.Synchronized(new Hashtable());
lock (ht.SyncRoot)
{
//一些操作
}
Synchronized表示返回一个线程安全的Hashtable,什么样的 hashtable才是一个线程安全的呢?下边我们就从.NET的源码开始理解。
public static Hashtable Synchronized(Hashtable table)
{
if (table == null)
{
throw new ArgumentNullException("table");
}
return new SyncHashtable(table);
}
从源码不难看出,Synchronized方法返回的其实是一个SynchHashtable类型的实例。在前边我们说过,Synchronized表示返回一个线程安全的Hashtable,从这个解释不难看出,SynchHashtable应该是继承自Hashtable。下边我们验证一下。看看 SynchHashtable类型的源码: Code
[Serializable]
private class SyncHashtable : Hashtable
{
// Fields
protected Hashtable _table;
// Methods
internal SyncHashtable(Hashtable table) : base(false)
{
this._table = table;
}
internal SyncHashtable(SerializationInfo info, StreamingContext context) : base(info, context)
{
this._table = (Hashtable) info.GetValue("ParentTable", typeof(Hashtable));
if (this._table == null)
{
throw new SerializationException(Environment.GetResourceString("Serialization_InsufficientState"));
}
}
public override void Add(object key, object value)
{
lock (this._table.SyncRoot)
{
this._table.Add(key, value);
}
}
public override void Clear()
{
lock (this._table.SyncRoot)
{
this._table.Clear();
}
}
public override object Clone()
{
lock (this._table.SyncRoot)
{
return Hashtable.Synchronized((Hashtable) this._table.Clone());
}
}
public override bool Contains(object key)
{
return this._table.Contains(key);
}
public override bool ContainsKey(object key)
{
return this._table.ContainsKey(key);
}
public override bool ContainsValue(object key)
{
lock (this._table.SyncRoot)
{
return this._table.ContainsValue(key);
}
}
public override void CopyTo(Array array, int arrayIndex)
{
lock (this._table.SyncRoot)
{
this._table.CopyTo(array, arrayIndex);
}
}
public override IDictionaryEnumerator GetEnumerator()
{
return this._table.GetEnumerator();
}
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
if (info == null)
{
throw new ArgumentNullException("info");
}
info.AddValue("ParentTable", this._table, typeof(Hashtable));
}
public override void OnDeserialization(object sender)
{
}
public override void Remove(object key)
{
lock (this._table.SyncRoot)
{
this._table.Remove(key);
}
}
internal override KeyValuePairs[] ToKeyValuePairsArray()
{
return this._table.ToKeyValuePairsArray();
}
// Properties
public override int Count
{
get
{
return this._table.Count;
}
}
public override bool IsFixedSize
{
get
{
return this._table.IsFixedSize;
}
}
public override bool IsReadOnly
{
get
{
return this._table.IsReadOnly;
}
}
public override bool IsSynchronized
{
get
{
return true;
}
}
public override object this[object key]
{
get
{
return this._table[key];
}
set
{
lock (this._table.SyncRoot)
{
this._table[key] = value;
}
}
}
public override ICollection Keys
{
get
{
lock (this._table.SyncRoot)
{
return this._table.Keys;
}
}
}
public override object SyncRoot
{
get
{
return this._table.SyncRoot;
}
}
public override ICollection Values
{
get
{
lock (this._table.SyncRoot)
{
return this._table.Values;
}
}
}
}
Collapse Methods
呵呵,果然不出我们所料,SyncHashtable果然继承自Hashtable,SyncHashtable之所有能实现线程的安全操作,就是因为在他们的一些方法中,就加了lock,我们知道,哪一个线程执行了lock操作,在他还没有释放lock之前,其他线程都要处于堵塞状态。 SyncHashtable就是通过这种方法,来实现所谓的线程安全。
现在我们理解了Synchronized的含义和用法,那接下来我们看看他和SyncRoot之间的关系。
SyncRoot表示获取可用于同步 Hashtable 访问的对象,老实说,这个解释不好理解,要想真正理解他的用法,我们还得从源码开始: public virtual object SyncRoot
{
get
{
if (this._syncRoot == null)
{
Interlocked.CompareExchange(ref this._syncRoot, new object(), null);
}
return this._syncRoot;
}
}
如果您清楚Interlocked的用法,这段代码没什么难理解的了(不清楚的朋友找GOOGLE吧),Interlocked为多个线程共享的变量提供原子操作。原子操作就是单线程操作。在一个Hashtable实例中,不论我们在代码的任何位置调用,返回的都是同一个object类型的对象。我们在开始写的 lock(ht.SyncRoot)和下边的操作作用是一样的.
static object obj = new object();
lock(obj)
{
// 一些操作
}
他们之间不同的是,我们声明的static object类型对象是类型级别的,而SyncRoot是对象级别的。
通过上面的分析,我们都应该能理解Synchronized 和 SyncRoot用法,他们之间的关系就是:
Hashtable 通过Synchronized方法,生成一个SynchHashtable类型的对象,在这个对象的一个方法中,通过lock (this._table.SyncRoot)这样的代码来实现线程安全的操作,其中this._table.SyncRoot返回的就是一个 object类型的对象,在一个SynchHashtable对象实例中,不管我们调用多少次,他是唯一的。
另外,针对泛型集合的线程安全访问,由于泛型集合中没有直接公布SyncRoot属性,所以猛一看好似无从下手。
但是查看集合泛型集合的源代码后就可发现他们实际上都提供了SyncRoot属性。
以下以Queue<T>集合为例。
bool ICollection.IsSynchronized
{
get
{
return false;
}
}
object ICollection.SyncRoot
{
get
{
if (this._syncRoot == null)
{
Interlocked.CompareExchange(ref this._syncRoot, new object(), null);
}
return this._syncRoot;
}
}
从以上源代码可以看出,这两个方法都被实现为了private,不过使用ICollection接口还是可以访问的。
lock (((ICollection)_queue).SyncRoot)
{
int item = _queue.Dequeue();
}
C# Synchronized 和 SyncRoot 实现线程同步的源码分析及泛型集合的线程安全访问的更多相关文章
- Solr4.8.0源码分析(3)之index的线程池管理
Solr4.8.0源码分析(3)之index的线程池管理 Solr建索引时候是有最大的线程数限制的,它由solrconfig.xml的<maxIndexingThreads>8</m ...
- java线程池ThreadPoolExector源码分析
java线程池ThreadPoolExector源码分析 今天研究了下ThreadPoolExector源码,大致上总结了以下几点跟大家分享下: 一.ThreadPoolExector几个主要变量 先 ...
- HDFS源码分析数据块复制监控线程ReplicationMonitor(二)
HDFS源码分析数据块复制监控线程ReplicationMonitor(二)
- Okhttp同步请求源码分析
进阶android,OKhttp源码分析——同步请求的源码分析 OKhttp是我们经常用到的框架,作为开发者们,我们不单单要学会灵活使用,还要知道他的源码是如何设计的. 今天我们来分析一下OKhttp ...
- HDFS源码分析数据块复制监控线程ReplicationMonitor(一)
ReplicationMonitor是HDFS中关于数据块复制的监控线程,它的主要作用就是计算DataNode工作,并将复制请求超时的块重新加入到待调度队列.其定义及作为线程核心的run()方法如下: ...
- python线程同步原语--源码阅读
前面两篇文章,写了python线程同步原语的基本应用.下面这篇文章主要是通过阅读源码来了解这几个类的内部原理和是怎么协同一起工作来实现python多线程的. 相关文章链接:python同步原语--线程 ...
- 同步锁源码分析(一)AbstractQueuedSynchronizer原理
文章转载自 AbstractQueuedSynchronizer的介绍和原理分析 建议去看一下原文的评论,会有不少收获. 简介 AbstractQueuedSynchronizer 提供了一个基于FI ...
- 线程池ThreadPoolExecutor源码分析
在阿里编程规约中关于线程池强制了两点,如下: [强制]线程资源必须通过线程池提供,不允许在应用中自行显式创建线程.说明:使用线程池的好处是减少在创建和销毁线程上所消耗的时间以及系统资源的开销,解决资源 ...
- ThreadPoolExecutor(线程池)源码分析
1. 常量和变量 private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); // 高3位为线程池的运行状态,低29 ...
随机推荐
- Plugin with id 'com.novoda.bintray-release' not found.的解决方案
import Module的时候,有时候会提示Plugin with id 'com.novoda.bintray-release' not found. 点击Open File,定位到该Module ...
- Python快速学习05:面向对象
系列文章:[传送门] Python对象是Python语言的核心部分.Python使用类(class)和对象(object),进行面向对象(object-oriented programming,简称O ...
- Eureka客户端注册多网卡下IP选择问题
在使用Spring Cloud多人协作开发时有一个场景:我本机启动了Eureka注册中心,其他人机器需要将服务注册到我本机的Eureka.(服务端和客户端在不同机器上) 这时出现了一个问题:服务成功注 ...
- Consul安装使用
安装 安装环境: Mac 我参照官网下载,然后解压,然后添加到PATH,并不能用.最终使用brew安装成功. brew install consul 安装成功后,文件位于/usr/local/Cell ...
- c#调用c++ dll的一个例子
1.创建一个简单的c++ 项目生成动态库. Vs 创建完工程后,打开SampleOperation.cpp文件,看到有个导出函数的例子. 复制这段代码, 修改函数(返回值, 参数列表, 函数的实现) ...
- centos7下安装samba服务器
samba笔记: http://services.linuxpanda.tech/%E7%BD%91%E7%BB%9C%E6%96%87%E4%BB%B6%E5%85%B1%E4%BA%AB/samb ...
- Java——构造方法和匿名对象
前言 在编写程序时不安全的初始化会导致程序发生发生重大错误.为了使程序可以被安全地初始化,C++引入了构造器(也可以成为构造方法)的概念,这是一个在创建对象时被自动调用的特殊方法.Java中也采用了构 ...
- linux的文档和目录结构
在Linux底下,所有的文件与目录都是由根目录开始,是目录与文件的源头,然后一个个的分支下来,如同树枝状,因此称为这种目录配置为:目录树. 目录树的特点是什么呢? 目录树的起始点是根目录(/,root ...
- C#装箱和拆箱。
装箱:值类型-->引用类型. 拆箱:引用类型-->值类型 装箱:把值类型拷贝一份到堆里.反之拆箱. 具有父子关系 是拆装箱的条件之一. 所以: class Program { static ...
- Postman Post请求上传文件
Postman Post请求上传文件一.选择post请求方式,输入请求地址 二.填写Headers Key:Content-Type :Value:multipart/form-data 如下图 三. ...