C#多线程学习笔记十三

四大线程安全的并发集合类


C#4.0前所有的集合都是线程不安全的。

ConcurrentBag

从ILSpy中可见ConcurrentBag的数据结构:
在这里插入图片描述
ThreadLocal:线程可见性,每个线程有自己的存储内容
1.每个线程分配一个“链表”,这个“链表”可以认为是List(ThreadLocalList)
每当有Add操作,locals里面就有一份新增的数据【本线程可见】,同时head和next也是有数据的,因为算法中有一个steal方法即“偷盗”的行为。
在这里插入图片描述
在这里插入图片描述

Add:插入数据,且是链表中的头插法,
TryTake:获取数据并移除
TryPeek:只查看数据
如果有三个线程做Add操作,那么三个线程的数据槽中又都有一份子集数据
t1 :1 2 3 locals
t2 :1 3 2 locals
t3: 2 3 4 locals
这时,如果在t3线程中执行了三个TryTake
t1 :1 2 3 locals
t2 :1 3 2 locals
t3:empty
如果在t3上再进行TryTake,他会到Bag的下一级的head和next中去找。
总结:ConcurrentBag就是利用线程槽来分摊Bag中的所有数据。
ConcurrentBag所有数据都是放置在多个插入线程的槽位中,每个线程一个子集。

ConcurrentStack

线程安全的stack是使用链表的形式,而同步版本是用数组实现的。
线程安全的stack是使用InterLocked来实现线程安全。而没有使用内核锁。

ConcurrentQueue

线程安全的queue也是使用链表的形式,而同步版本是用数组实现的

ConcurrentDictionary

线程安全的并发集合类使用方法如下:

            ConcurrentBag<int> bag = new ConcurrentBag<int>();
            bag.Add(1);
            bag.Add(2);
            var resultBag = 0;
            bag.TryTake(out resultBag);
            Console.WriteLine(resultBag);

            ConcurrentStack<int> stack = new ConcurrentStack<int>();
            stack.Push(1);
            stack.Push(2);
            var resultSatck = 0;
            stack.TryPop(out resultSatck);
            Console.WriteLine(resultSatck);

            ConcurrentQueue<int> queue = new ConcurrentQueue<int>();
            queue.Enqueue(1);
            queue.Enqueue(2);
            var resultQueue = 0;
            queue.TryDequeue(out resultQueue);
            Console.WriteLine(resultQueue);

            ConcurrentDictionary<int,int> dictionary = new ConcurrentDictionary<int,int>();
            dictionary.TryAdd(1,1);
            dictionary.TryAdd(2,2);
            var resultDictionary = 0;
            dictionary.TryRemove(1, out resultDictionary);
            Console.WriteLine(resultDictionary);

猜你喜欢

转载自blog.csdn.net/Z960515/article/details/113444247