ConcurrentDictionary测试

经过测试发现,多线程操作都是安全的。甚至包括在遍历的时候,进行删除操作

https://github.com/ChuckTest/ConcurrentTest

 class Program
    {
        private static readonly ConcurrentDictionary<int, int> Dictionary = new ConcurrentDictionary<int, int>();
        private static readonly List<string> AddSuccessfully = new List<string>();
        private static readonly List<string> RemoveSuccessfully = new List<string>();
        private static readonly List<string> IterateString = new List<string>();
        private static int _tryRemoveCount;
        private static readonly Random Random = new Random();
        static void Main(string[] args)
        {
            try
            {
                int j = 0;
                for (int i = 1; i <= 12; i++)
                {
                    j++;
                    Thread thread;
                    if (j == 1)
                    {
                        thread = new Thread(DoTask1);
                    }
                    else if(j == 2)
                    {
                        thread = new Thread(DoTask2);
                    }
                    else if (j == 3)
                    {
                        thread = new Thread(DoTask3);
                        j = 0;
                    }
                    else
                    {
                        throw new Exception();
                    }
                    thread.IsBackground = false;
                    thread.Start(i);
                }

                Console.WriteLine("======");
                int timeout = 0;
                while (AddSuccessfully.Count != 100)
                {
                    timeout++;
                    Thread.Sleep(1000);
                    if (timeout > 5)
                    {
                        break;
                    }
                }
                
                timeout = 0;
                while (_tryRemoveCount != 5)
                {
                    timeout++;
                    Thread.Sleep(1000);
                    if (timeout > 5)
                    {
                        break;
                    }
                }

                Console.WriteLine($"addSuccessfully.Count = {AddSuccessfully.Count}");
                foreach (var item in AddSuccessfully)
                {
                    Console.WriteLine(item);
                }

                Console.WriteLine($"removeSuccessfully.Count = {RemoveSuccessfully.Count}");
                foreach (var item in RemoveSuccessfully)
                {
                    Console.WriteLine(item);
                }

                Console.WriteLine($"IterateString.Count = {IterateString.Count}");
                foreach (var item in IterateString)
                {
                    Console.WriteLine(item);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
            finally
            {
                Console.ReadLine();
            }
        }

        public static void DoTask1(object obj)
        {
            Console.WriteLine($"DoTask1 with {obj} Thread id = {Thread.CurrentThread.ManagedThreadId}");
            for (int i = 0; i < 100; i++)
            {
                var flag = Dictionary.TryAdd(i,i);
                if (flag)
                {
                    AddSuccessfully.Add($"DoTask1 with {obj} add {i} successfully {DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}");
                    //Console.WriteLine();
                }
                Thread.Sleep(1);
            }
        }

        public static void DoTask2(object obj)
        {
            _tryRemoveCount++;
            Console.WriteLine(
                $"DoTask2 with {obj} Thread id = {Thread.CurrentThread.ManagedThreadId}, count = {Dictionary.Count}");
            var toRemove = Random.Next(0, 100);
            for (int i = 0; i < 100; i++)
            {
                var flag = Dictionary.TryRemove(toRemove, out _);
                if (flag)
                {
                    RemoveSuccessfully.Add($"DoTask2 with {obj} remove {toRemove} successfully. {DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}");
                }
                Thread.Sleep(1);
            }
        }

        public static void DoTask3(object obj)
        {
            _tryRemoveCount++;
            Console.WriteLine(
                $"DoTask3 with {obj} Thread id = {Thread.CurrentThread.ManagedThreadId}, count = {Dictionary.Count}");
            foreach (var item in Dictionary)
            {
                IterateString.Add($"DoTask3 with {obj} iterate {item.Key} {DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}");
                Thread.Sleep(2);
            }
        }
    }
[__DynamicallyInvokable]
public bool TryAdd(TKey key, TValue value)
{
    if (key == null)
    {
        throw new ArgumentNullException("key");
    }
    TValue tvalue;
    return this.TryAddInternal(key, value, false, true, out tvalue);
}
private bool TryAddInternal(TKey key, TValue value, bool updateIfExists, bool acquireLock, out TValue resultingValue)
        {
            ConcurrentDictionary<TKey, TValue>.Tables tables;
            IEqualityComparer<TKey> comparer;
            bool flag;
            bool flag3;
            for (;;)
            {
                tables = this.m_tables;
                comparer = tables.m_comparer;
                int hashCode = comparer.GetHashCode(key);
                int num;
                int num2;
                this.GetBucketAndLockNo(hashCode, out num, out num2, tables.m_buckets.Length, tables.m_locks.Length);
                flag = false;
                bool flag2 = false;
                flag3 = false;
                try
                {
                    if (acquireLock)
                    {
                        Monitor.Enter(tables.m_locks[num2], ref flag2);
                    }
                    if (tables != this.m_tables)
                    {
                        continue;
                    }
                    int num3 = 0;
                    ConcurrentDictionary<TKey, TValue>.Node node = null;
                    for (ConcurrentDictionary<TKey, TValue>.Node node2 = tables.m_buckets[num]; node2 != null; node2 = node2.m_next)
                    {
                        if (comparer.Equals(node2.m_key, key))
                        {
                            if (updateIfExists)
                            {
                                if (ConcurrentDictionary<TKey, TValue>.s_isValueWriteAtomic)
                                {
                                    node2.m_value = value;
                                }
                                else
                                {
                                    ConcurrentDictionary<TKey, TValue>.Node node3 = new ConcurrentDictionary<TKey, TValue>.Node(node2.m_key, value, hashCode, node2.m_next);
                                    if (node == null)
                                    {
                                        tables.m_buckets[num] = node3;
                                    }
                                    else
                                    {
                                        node.m_next = node3;
                                    }
                                }
                                resultingValue = value;
                            }
                            else
                            {
                                resultingValue = node2.m_value;
                            }
                            return false;
                        }
                        node = node2;
                        num3++;
                    }
                    if (num3 > 100 && HashHelpers.IsWellKnownEqualityComparer(comparer))
                    {
                        flag = true;
                        flag3 = true;
                    }
                    Volatile.Write<ConcurrentDictionary<TKey, TValue>.Node>(ref tables.m_buckets[num], new ConcurrentDictionary<TKey, TValue>.Node(key, value, hashCode, tables.m_buckets[num]));
                    checked
                    {
                        tables.m_countPerLock[num2]++;
                        if (tables.m_countPerLock[num2] > this.m_budget)
                        {
                            flag = true;
                        }
                    }
                }
                finally
                {
                    if (flag2)
                    {
                        Monitor.Exit(tables.m_locks[num2]);
                    }
                }
                break;
            }
            if (flag)
            {
                if (flag3)
                {
                    this.GrowTable(tables, (IEqualityComparer<TKey>)HashHelpers.GetRandomizedEqualityComparer(comparer), true, this.m_keyRehashCount);
                }
                else
                {
                    this.GrowTable(tables, tables.m_comparer, false, this.m_keyRehashCount);
                }
            }
            resultingValue = value;
            return true;
        }

[__DynamicallyInvokable]
public bool TryAdd(TKey key, TValue value)
{
    
if (key == null)
    
{
        
throw new ArgumentNullException("key");
    
}
    
TValue tvalue;
    
return this.TryAddInternal(key, value, false, true, out tvalue);
}

原文地址:https://www.cnblogs.com/chucklu/p/12871201.html