在我的代码中,我有一个静态字典对象
private static IDictionary< ConnKey, DbConnection > ConnectionList = new Dictionary< ConnKey, DbConnection >( );
抛出此错误
System.IndexOutOfRangeException: Index was outside the bounds of the array.
at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value)
我搜索并发现这是因为多个线程尝试访问字典,但我在字典上有lock
lock( ConnectionList ) {
ConnectionList.Add( key, res );
}
然后我搜索了更多,发现字典上的锁定并不会阻止对它的所有操作,所以我应该在lock
对象SyncRoot
上使用它来实现我想要的1}
lock( ((IDictionary)ConnectionList).SyncRoot) {
但后来我搜索到使用SyncRoot
并不是一个好习惯
在进一步搜索中,我发现有ConcurrentDictionary
用于此目的
ConcurrentDictionary
,我仍然需要使用lock
,否则它会自行处理所有内容。ConcurrentDictionary
上使用锁定,我必须直接使用lock
,或者我必须再次锁定SyncRoot
对象提前致谢!
答案 0 :(得分:15)
使用Dictionary<,>
,你必须锁定读写。所以两者
lock( ConnectionList ) {
ConnectionList.Add( key, res );
}
和
lock( ConnectionList ) {
res = ConnectionList[ key ];
}
和
lock( ConnectionList ) {
int cnt = ConnectionList.Count;
}
和
lock( ConnectionList ) {
ConnectionList.Clear();
}
和
lock( ConnectionList ) {
foreach ( var kv in ConnectionList ) {
// Do things
}
}
依此类推: - )
使用ConcurrentDictionary<,>
您不需要任何锁定,但请注意语法与Dictionary<,>
答案 1 :(得分:3)
那么有人可以建议我锁定字典的最佳方法是什么?
如果您想继续使用经典Dictionary<,>
AFAK,您必须查看由Dictionary实现的ICollection
界面并使用属性ICollection.SyncRoot
根据定义
<强> MSDN 强>
Gets an object that can be used to synchronize access to the ICollection.
所以为了达到这个目的,你可以做这样的事情
如果我使用ConcurrentDictionary,我仍然需要使用锁定,否则它将自己处理所有内容。
来自MSDN
ConcurrentDictionary专为多线程场景而设计。您不必在代码中使用锁来添加或删除集合中的项。但是,一个线程总是可以检索一个值,另一个线程可以通过为相同的键提供一个新值来立即更新集合。
如果我必须在ConcurrentDictionary上使用锁,我必须直接使用锁或者再次使用它来锁定它的SyncRoot对象
是的,如果您希望在使用lock
或SyncRoot
方法时执行Atomic方法,则必须在GetOrAdd
上使用AddOrUpdate
答案 2 :(得分:2)
- 所以有人可以建议我哪种方法可以锁定字典
醇>
您可以使用它SyncRoot
或创建您在访问字典对象时锁定的私有对象,例如
private static object _sybcRoot = new object();
public static void Add( string key, string res)
lock( _sybcRoot ) {
ConnectionList.Add( key, res );
}
}
- 如果我使用ConcurrentDictionary,我仍然需要使用锁定,否则它会自行处理所有内容。
醇>
不,使用任何Concurrent*
集合时无需锁定。它在设计上是线程安全的,但是这种语法略有不同。 Concurrent*
集合使用无锁方法,在没有许多线程竞争访问(乐观并发)的情况下,这种方法更好
- 如果我必须在ConcurrentDictionary上使用锁,我必须直接使用锁或者再次使用它来锁定它的SyncRoot对象
醇>
您必须使用相同的锁定对象来保护对相同资源的访问。否则线程可能“认为”资源是免费的,而实际上它被其他线程使用,恰好将其锁定在另一个对象的同步根上。