在我的代码中,我有一个静态字典对象
private static IDictionary< ConnKey, DbConnection > ConnectionList = new Dictionary< ConnKey, DbConnection >( );
Run Code Online (Sandbox Code Playgroud)
这就是抛出这个错误
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)
Run Code Online (Sandbox Code Playgroud)
我搜索并发现这是因为多个线程尝试访问字典,但我确实lock
在字典上
lock( ConnectionList ) {
ConnectionList.Add( key, res );
}
Run Code Online (Sandbox Code Playgroud)
然后我搜索了更多,发现字典上的锁并没有阻止它上面的所有操作,所以我应该像这样使用lock
它的SyncRoot
对象来实现我想要的
lock( ((IDictionary)ConnectionList).SyncRoot) {
Run Code Online (Sandbox Code Playgroud)
但后来我搜索到使用SyncRoot
不是一个好习惯
在进一步搜索中,我发现有一个ConcurrentDictionary
用于此目的
ConcurrentDictionary
,我仍然需要使用lock
它或它将自己处理一切.ConcurrentDictionary
,我必须lock
直接或再次使用它我必须SyncRoot
为它锁定对象提前致谢!
我试图理解ICollection中syncroot的意义.为什么不直接锁定集合?
lock(myCollection)
{
//do stuff to myCollection
}
Run Code Online (Sandbox Code Playgroud)
VS
lock(myCollection.SyncRoot)
{
//do stuff to myCollection
}
Run Code Online (Sandbox Code Playgroud) 我是SyncRoot概念的新手.据我所知,用于锁定的对象应该是私有的.
但是HashTable
有一个公共属性,SyncRoot
它只是一个私有SyncRoot对象的包装器.它建议你锁定HashTable.SyncRoot
枚举该集合的时候.
看起来我们可能会失败,因为它不再是私有的.它真的是线程安全吗?
如果我制作自己的私人锁定机制怎么办?
private readonly object _syncObject;
哪一个更好,为什么?
我在 Blazor 服务器应用程序的范围服务中有 2 个字典,我用它来管理多租户的状态。我注意到用户在不同线程上修改字典可能存在并发问题。
public Dictionary<string, GlobalDataModel> Global { get; } = new();
public Dictionary<string, Dictionary<long, LocalDataModel>> Local { get; } = new();
Run Code Online (Sandbox Code Playgroud)
我想我倾向于将它们保留为普通字典并在修改或迭代时锁定同步根。
如果我要将一个项目添加到包含类中的集合中,它会是:
if (Local.ContainsKey(tenantId) == false)
{
lock (syncRoot)
{
Local.Add(tenantId, new Dictionary<long, LocalDataModel>());
}
}
Run Code Online (Sandbox Code Playgroud)
或者:
lock (syncRoot)
{
if (Local.ContainsKey(tenantId) == false)
{
{
Local.Add(tenantId, new Dictionary<long, LocalDataModel>());
}
}
}
Run Code Online (Sandbox Code Playgroud)
那么,如果我要将服务集合的不同部分从外部类复制到列表中,以便可以安全地迭代它,我是否只锁定在服务级别、字典级别或数据模型级别,或者它是依赖的?
假设我想要一个特定项目中的资源集合。可不可能是:
[Inject] private IDataAdaptor DataAdaptor { get; set; };
var resources;
lock (DataAdaptor)
{
resources = DataAdaptor.Local[TenantId][ProjectId].Resources;
}
Run Code Online (Sandbox Code Playgroud)
或者:
lock (DataAdaptor.Local[TenantId][ProjectId].Resources)
{ …
Run Code Online (Sandbox Code Playgroud)