我正在使用ConcurrentDictionary<String,List<String>>
。我想使用AddOrUpdate
方法,以便如果某个键已存在列表,则该值将添加到值列表中。由于我提供给AddOrUpdate
方法的函数需要返回List,我想我想这样做:
public void AddValue( String key, String value)
{
_dictionary.AddOrUpdate( key, new List<string> { value},
( k, oldValue ) => UpdateValueList( oldValue, value) );
}
private List<String> UpdateValueList( List<String> list, String value)
{
if ( !list.Contains( value) )
{
list.Add( value);
}
return list;
}
这是处理这种情况的好方法,还是我应该做些不同的事情?
答案 0 :(得分:1)
鉴于您正在使用ConcurrentDictionary
我假设您正在寻找线程安全的解决方案。您的解决方案不是线程安全的,因为List<T>
类不是线程安全的。
要创建一个线程安全的解决方案,您需要确保同步所有类中List<T>
类的访问权限,并确保您永远不要在您的课外公开List(如果您需要,那么'我需要克隆它。)
如果不了解更多关于你想要实现的目标,就很难更准确。
<强>更新强>
仅提供缺乏线程安全性的示例。
考虑调用AddOrUpdate方法的两个线程之间的竞争条件。
ConcurrentDictionary
和addValueFactory
方法时, updateValueFactory
没有锁定。这是一般设计原则:在调用外部代码时不要持有锁,因为这会导致各种问题,包括重入。
因此,两个线程可以使用相同的输入列表同时运行UpdateValueList
方法,这不是线程安全的。
如果你在锁中包含对列表的每个访问权限,它可能会成为线程安全的,但是我需要看到你的类的其余代码才能确定。
答案 1 :(得分:1)
是的,我意识到这很老了,但是找不到一个好的答案,所以将我的解决方案放在这里以帮助他人。
给出一个ConcurrentDictionary,其中值是您要添加值的集合(列表,ConcurentBag等)。
ConcurrentDictionary<int, ConcurrentBag<int>> myDictionary =
new ConcurrentDictionary<int, ConcurrentBag<int>>();
检查密钥是否存在,如果没有,请添加密钥并初始化您的收藏集。
if (!myDictionary.ContainsKey(myKey))
{
myDictionary.TryAdd(
key: myKey,
value: new ConcurrentBag<int>());
}
现在您知道密钥在那里并且可以修改您的集合,将您的值添加到集合中。
myDictionary[myKey].Add(myValue);
带有数据的完整示例:
static void concurentDictionaryList()
{
ConcurrentDictionary<int, ConcurrentBag<int>> myDictionary = new ConcurrentDictionary<int, ConcurrentBag<int>>(); //Dictionary containing a List
int[][] mySampleValues = new int[10][]; //Collection Of sample Data
int myKey;
int myValue;
//Build Some Sample Data
for (int i = 0; i < 10; i++)
{
mySampleValues[i] =
Enumerable.Range(
start: 1,
count: mySampleValues.Length - i)
.ToArray();
}
//Loop through each sample value
for (int i = 0; i < mySampleValues.Length; i++)
{
myValue = //Get the value I want to add to each key;
i;
//Loop though each sample value's collection
for (int ii = 0; ii < mySampleValues[i].Length; ii++)
{
myKey =
mySampleValues[i][ii]; //Get the value I'll use for the key
if (!myDictionary.ContainsKey(myKey))
{
myDictionary.TryAdd( // If the key doesn't exist in the dictionary,
key: myKey, // then add the key and initilize the List for that key
value: new ConcurrentBag<int>());
}
myDictionary[myKey].Add(myValue); // Since I know the key is in the Dictionary
// and the list has been initilized,
// I just add the value to my list.
}
}
//Validate by printing
foreach (var itemKey in myDictionary.Keys)
{
Debug.WriteLine(""
+$"{itemKey.ToString().PadLeft(2, ' ')}: "
+$"{string.Join(separator: ", ",values: myDictionary[itemKey].ToArray().OrderBy(o=>o))}");
}
//Printed Results:
// 1: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
// 2: 0, 1, 2, 3, 4, 5, 6, 7, 8
// 3: 0, 1, 2, 3, 4, 5, 6, 7
// 4: 0, 1, 2, 3, 4, 5, 6
// 5: 0, 1, 2, 3, 4, 5
// 6: 0, 1, 2, 3, 4
// 7: 0, 1, 2, 3
// 8: 0, 1, 2
// 9: 0, 1
//10: 0
}
**注意:选择集合类型时,请注意该线程中已有的线程安全注释。