伟德体育官网 58

ConcurrentBag的实现原理,Java集合类工作原理及实现

目录

群集类的得以完成原理

集合

 


 

1.成团接口和品种

接口

说明

IEnumerable<T>

如果foreach语句用于集合,就需要IEnumerable接口.这个借口定义了方法GetEnumerator(),他返回一个实现了IEnumerator接口的枚举

ICollection<T>

ICollection<T>接口有泛型集合类实现.使用这个借口可以获得集合中的元素个数(Count属性),把集合复制到数组中(CopyTo()方法),还可以从集合中添加和删除元素(Add(),Remove(),Clear())

List<T>

IList<T>接口用于可通过位置访问其中的元素列表,这个接口定义了一个 索引器,可以在集合的指定位置插入或删除 mount些项(Insert()和Remove()方法).IList<T>接口派生自ICollection<T>接口

ISet<T>

ISet<T>接口是.NET4中新增的.实现这个接口的集允许合并不同的集.获得两个集的交集,检查两个集合是否重叠.ISet<T>接口派生自ICollection<T>接口

IDictionary<TKey,TValue>

IDictionary<TKey,TValue>接口由包含键和值的泛型集合类 实现.使用这个接口可以访问所有的键和值,使用键类型的索引器可以访问某些项,还可以添加或删除某些项

ILookup<TKey,TValue>

ILookup<TKey,TValue>接口类似于IDictionary<TKey,TValue>接口,实现该接口的集合有键和值,且可以通过一个键包含多个值

IComparer<T>

接口ICommparer<T>由比较器实现,通过Comparer()方法给集合中的元素排序

IEqualityComparer<T>

接口IEqualityComparer<T>由一个比较器实现,该比较器可用于字典中的键.使用这个接口,可以对对象进行相等性比较.在.NET中,这个接口也由数组和元组实现

IProducerConsumerColllection<T>

IProducerConsumerCollection<T>接口是.NET4中新增的,它支持新的线程安全的集合类

IReadOnlyList<T>、

IReadOnlyDictionary<T>、

IReadOnlyCollection<T>

初始化后不能修改的集合,只能检索对象,不能添加和删除.

 

2.列表

先看看多个实例:

伟德体育官网 1伟德体育官网 2

[Serializable]
  public class Racer : IComparable<Racer>, IFormattable
  {
    public int Id { get; private set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Country { get; set; }
    public int Wins { get; set; }

    public Racer(int id, string firstName, string lastName, string country)
      : this(id, firstName, lastName, country, wins: 0)
    {
    }
    public Racer(int id, string firstName, string lastName, string country, int wins)
    {
      this.Id = id;
      this.FirstName = firstName;
      this.LastName = lastName;
      this.Country = country;
      this.Wins = wins;
    }

    public override string ToString()
    {
      return String.Format("{0} {1}", FirstName, LastName);
    }

    public string ToString(string format, IFormatProvider formatProvider)
    {
      if (format == null) format = "N";
      switch (format.ToUpper())
      {
        case null:
        case "N": // name
          return ToString();
        case "F": // first name
          return FirstName;
        case "L": // last name
          return LastName;
        case "W": // Wins
          return String.Format("{0}, Wins: {1}", ToString(), Wins);
        case "C": // Country
          return String.Format("{0}, Country: {1}", ToString(), Country);
        case "A": // All
          return String.Format("{0}, {1} Wins: {2}", ToString(), Country, Wins);
        default:
          throw new FormatException(String.Format(formatProvider,
                "Format {0} is not supported", format));
      }
    }

    public string ToString(string format)
    {
      return ToString(format, null);
    }

    public int CompareTo(Racer other)
    {
      if (other == null) return -1;
      int compare = string.Compare(this.LastName, other.LastName);
      if (compare == 0)
        return string.Compare(this.FirstName, other.FirstName);
      return compare;
    }
  }

View Code

  • 一、前言
  • 二、ConcurrentBag类
  • 三、
    ConcurrentBag线程安全达成原理

    • 1.
      ConcurrentBag的个体字段
    • 2.
      用于数据存款和储蓄的TrehadLocalList类
    • 3.
      ConcurrentBag贯彻新添成分
    • 4. ConcurrentBag
      怎么样促成迭代器形式
  • 四、总结
  • 小编水平有限,如若不当款待各位商量指正!

LRUCache原理

核心算法
map:存放数据的集合    new LinkedHashMap<K, V>(0, 0.75f, true);
size:当前LruCahce的内存占用大小
maxSize:Lrucache的最大容量
putCount:put的次数
createCount:create的次数
evictionCount:回收的次数
hitCount:命中的次数
missCount:丢失的次数

Lru是近来最少使用算法的简单称谓,意思呢就是查询出以来的岁月利用次数起码的极度目的。设置为true的时候,若是对二个因素举行了操作(put、get卡塔尔(قطر‎,就能把极度成分放到集合的结尾,设置为false的时候,无论怎么操作,集结成分的相继都以根据插入的逐条来实行仓储的。
算法大旨:当内容容积达到最大值的时候,只必要移除那么些集结的前头的要素直到集合的体积丰裕存款和储蓄数据的时候就足以了。

创办列表

利用暗中同意的布局函数创设几个空驶列车表,元素加多到列表后,列表容积会扩充到可吸收接纳4个要素。
要是增添了第5个成分,列表大小会重新安装为8个因素。每趟都会将列表的容积重新安装为本来的2倍.

var intList=new List<int>();

 

比如列表的体量变了,整个会集将在重新分配到新的内部存储器块中,大家得以在开首化时设置它的体积:

List<int> intList=new List<int>(10);

只要列表的个数超过11个,能够设置体量Capacity:

intList.Capacity = 20;

设若列表的成分已经加多完了,列表会设有多余的体量空间。能够使用TrimExcess方法去除不要的体积:

intList.TrimExcess();

a.集结伊始值设定项

行使开始化构造器初阶化设定项

int[] arr = { 1, 2, 3 };
var intList = new List<int>(arr) ;

括号中初步化

var intList = new List<int>() { 4, 5 };

 

b.添日币素

intList.Add(5);

丰裕数组

intList.AddRange(new int[] { 3, 5 });

c.插入成分

intList.Insert(3, 4);

d.访谈成分

采取索引获取:

var value = intList[3];

巡回遍历:

foreach (var item in intList)
{
     var res = item;
}

forEach方法:

class List<T> : IList<T>
{
    private T[] items;
    public void forEach(Action<T> action)
    {
        if (action == null) throw new ArgumentNullException("action");
        foreach (var item in items)
        {
            action(item);
        }
    }
}

接下来大家得以这么调用:

intList.ForEach(m => Console.WriteLine(m));

e.删除成分

按索引删除,一点也不慢

intList.RemoveAt(3);

按成分值删除

intList.Remove(4);

f.搜索

在聚聚焦寻觅成分。能够搜寻索引和因素。

FindIndex通过相称元素值,获得索引:

intList.FindIndex(m => m==4);

FindIndex方法参数Predicate<T>传入相配的表明式,再次回到相配的成分索引值,Predicate<T>委托代表定义少年老成组条件并分明钦定对象是或不是适合这几个条件的方法

intList.Find(m => m == 4);
intList.FindAll(m => m > 2);

Find重返了杰出原则的成分值,FindAll重临了同盟原则的具有因素

g.排序

列表使用Sort方法开展成分排序

intList.Sort();

intList.Sort((m, n) => m);

Sort(Comparison<T>
comparison卡塔尔方法参数中的委托Comparison含有2个参数,方法将这2个因素举办比较,然后返圮相对值,若是回去-1的,成分须求排前边,重回1的成分必要排前边.

Sort(IComparer<T>
comparer卡塔尔方法参数中是三个相比较接口,接口实现Comparer方法

伟德体育官网 3伟德体育官网 4

public enum CompareType
  {
    FirstName,
    LastName,
    Country,
    Wins
  }

  public class RacerComparer : IComparer<Racer>
  {
    private CompareType compareType;
    public RacerComparer(CompareType compareType)
    {
      this.compareType = compareType;
    }

    public int Compare(Racer x, Racer y)
    {
      if (x == null && y == null) return 0;
      if (x == null) return -1;
      if (y == null) return 1;

      int result;
      switch (compareType)
      {
        case CompareType.FirstName:
          return string.Compare(x.FirstName, y.FirstName);
        case CompareType.LastName:
          return string.Compare(x.LastName, y.LastName);
        case CompareType.Country:
          result = string.Compare(x.Country, y.Country);
          if (result == 0)
            return string.Compare(x.LastName, y.LastName);
          else
            return result;
        case CompareType.Wins:
          return x.Wins.CompareTo(y.Wins);
        default:
          throw new ArgumentException("Invalid Compare Type");
      }
    }
  }

View Code

 

h.类型转变

 Converter委托

public delegate TOutput Converter<in TInput, out TOutput>(TInput input);

ConvertAll可以将一种类型的集合转换为另一种类型的集合。

intList.ConvertAll(m => m.ToString());

HashMap

图解HashMap(一)/)

图解HashMap(二)/)

HashMap实际上是叁个“链表散列”的数据布局,即数组和链表的结合体

伟德体育官网 5

image.png

粗略地说,HashMap 在尾部将 key-value
当成一个完好无损举行管理,这些共同体便是贰个 Entry 对象。HashMap 底层选择贰个Entry[] 数组来保存全体的 key-value 对,当供给仓库储存多个 Entry
对象时,会基于 hash 算法来支配其在数组中的存储地方,在依靠 equals
方法决定其在该数组地方上的链表中的存储地方;当要求收取二个Entry
时,也会根据 hash 算法找到其在数组中的存款和储蓄地点,再依据 equals
方法从该岗位上的链表中收取该Entry。

扩容:当 HashMap 中的成分个数当先数组大小
loadFactor时,就交易会开数组扩大容积,loadFactor的暗中认可值为
0.75,那是一个折中的取值。也等于说,私下认可情形下,数组大小为 16,那么当
HashMap 相月素个数超越 16
0.75=12 的时候,就把数组的尺寸扩大为
2*16=32,即扩展学一年级倍,然后再次总结各样成分在数组中的地方,而这是二个十二分消耗品质的操作,所以若是大家曾经预感HashMap 瓜时素的个数,那么预设成分的个数能够有效的压实 HashMap 的属性。

Fail-Fast 机制:HashMap
不是线程安全的,由此意气风发旦在使用迭代器的历程中有其它线程改革了
map,那么将抛出 ConcurrentModificationException,那便是所谓 fail-fast
战略。
比方说:当某一个线程 A 通过
iterator去遍历某集结的进度中,若该集结的内容被别的线程所改造了;那么线程
A 访谈集适当时候,就能抛出ConcurrentModificationException 极度,产生fail-fast 事件。
得以完毕原理:判定 modCount 跟 expectedModCount
是不是等于,借使不等于就表示早原来就有别的线程校正了 Map。
减轻方案:提议使用“java.util.concurrent 包下的类”去顶替“java.util
包下的类”

遍历方式:
第一种:

   Map map = new HashMap();
  Iterator iter = map.entrySet().iterator();
  while (iter.hasNext()) {
  Map.Entry entry = (Map.Entry) iter.next();
  Object key = entry.getKey();
  Object val = entry.getValue();
    }

频率高,以往必要求选拔此种情势
第二种:

Map map = new HashMap();
  Iterator iter = map.keySet().iterator();
  while (iter.hasNext()) {
  Object key = iter.next();
  Object val = map.get(key);
  }

频率低,今后尽量少使用!

只读集合

创立会集后,它们是只读的。

3.队列

意味着了一个先进先出的对象集结。当您供给对各样举行先进先出的会见时,则动用队列。当你在列表中增添黄金年代项,称为入队,当你从列表中移除大器晚成项时,称为出队

增加队列成分时拉长lock,因为二十四线程可以何况做客,所以对队列进行锁定访问。

伟德体育官网 6

 

伟德体育官网 7伟德体育官网 8

using System;
using System.Collections;

namespace CollectionsApplication
{
   class Program
   {
      static void Main(string[] args)
      {
         Queue q = new Queue();

         q.Enqueue('A');
         q.Enqueue('M');
         q.Enqueue('G');
         q.Enqueue('W');

         Console.WriteLine("Current queue: ");
         foreach (char c in q)
            Console.Write(c + " ");
         Console.WriteLine();
         q.Enqueue('V');
         q.Enqueue('H');
         Console.WriteLine("Current queue: ");         
         foreach (char c in q)
            Console.Write(c + " ");
         Console.WriteLine();
         Console.WriteLine("Removing some values ");
         char ch = (char)q.Dequeue();
         Console.WriteLine("The removed value: {0}", ch);
         ch = (char)q.Dequeue();
         Console.WriteLine("The removed value: {0}", ch);
         Console.ReadKey();
      }
   }
}

View Code

当上边的代码被编写翻译和推行时,它会产生下列结果:

Current queue: 
A M G W 
Current queue: 
A M G W V H 
Removing values
The removed value: A
The removed value: M

伟德体育官网 9伟德体育官网 10

class Program
    {
        static void Main()
        {
            var dm = new DocumentManager();

            ProcessDocuments.Start(dm);

            // Create documents and add them to the DocumentManager
            for (int i = 0; i < 1000; i++)
            {
                Document doc = new Document("Doc " + i.ToString(), "content");
                dm.AddDocument(doc);
                Console.WriteLine("Added document {0}", doc.Title);
                Thread.Sleep(new Random().Next(20));
            }

        }
    }

Program

伟德体育官网 11伟德体育官网 12

public class ProcessDocuments
  {
    public static void Start(DocumentManager dm)
    {
      Task.Factory.StartNew(new ProcessDocuments(dm).Run);
    }

    protected ProcessDocuments(DocumentManager dm)
    {
      if (dm == null)
        throw new ArgumentNullException("dm");
      documentManager = dm;
    }

    private DocumentManager documentManager;

    protected void Run()
    {
      while (true)
      {
        if (documentManager.IsDocumentAvailable)
        {
          Document doc = documentManager.GetDocument();
          Console.WriteLine("Processing document {0}", doc.Title);
        }
        Thread.Sleep(new Random().Next(20));
      }
    }
  }

ProcessDocuments

伟德体育官网 13伟德体育官网 14

public class DocumentManager
  {
    private readonly Queue<Document> documentQueue = new Queue<Document>();

    public void AddDocument(Document doc)
    {
      lock (this)
      {
        documentQueue.Enqueue(doc);
      }
    }

    public Document GetDocument()
    {
      Document doc = null;
      lock (this)
      {
        doc = documentQueue.Dequeue();
      }
      return doc;
    }

    public bool IsDocumentAvailable
    {
      get
      {
        return documentQueue.Count > 0;
      }
    }
  }

DocumentManager

伟德体育官网 15伟德体育官网 16

public class Document
  {
    public string Title { get; private set; }
    public string Content { get; private set; }

    public Document(string title, string content)
    {
      this.Title = title;
      this.Content = content;
    }
  }

Document

4.栈

意味着了多个后进先出的目标集合。当你必要对各个进行后进先出的拜候时,则动用酒店。当您在列表中增多一项,称为推入要素,当您从列表中移除风流洒脱项时,称为弹出元素。

伟德体育官网 17

伟德体育官网 18伟德体育官网 19

class Program
    {
        static void Main()
        {
            var alphabet = new Stack<char>();
            alphabet.Push('A');
            alphabet.Push('B');
            alphabet.Push('C');

            Console.Write("First iteration: ");
            foreach (char item in alphabet)
            {
                Console.Write(item);
            }
            Console.WriteLine();

            Console.Write("Second iteration: ");
            while (alphabet.Count > 0)
            {
                Console.Write(alphabet.Pop());
            }
            Console.WriteLine();


        }
    }

Program

First iteration: CBA
Second iteration: CBA

5.链表

LinkedList<T>是三个双向链表,其成分指向它前边和前边的因素,那样经过运动下多个要素就能够正向遍历整个链表。通过活动到前多少个元素得以反向遍历那个链表

链表的长处是,假使将元素插入列表的高级中学级地点,使用链表会异常的快,在插入一个因素时,只供给改进上二个要素的Next援用和下二个成分的Previous援用,使他们引用所插入的因素。

伟德体育官网 20伟德体育官网 21

public class Document
  {
    public string Title { get; private set; }
    public string Content { get; private set; }
    public byte Priority { get; private set; }

    public Document(string title, string content, byte priority)
    {
      this.Title = title;
      this.Content = content;
      this.Priority = priority;
    }
  }

Document

伟德体育官网 22伟德体育官网 23

public class PriorityDocumentManager
  {
    private readonly LinkedList<Document> documentList;

    // priorities 0.9
    private readonly List<LinkedListNode<Document>> priorityNodes;

    public PriorityDocumentManager()
    {
      documentList = new LinkedList<Document>();

      priorityNodes = new List<LinkedListNode<Document>>(10);
      for (int i = 0; i < 10; i++)
      {
        priorityNodes.Add(new LinkedListNode<Document>(null));
      }
    }

    public void AddDocument(Document d)
    {
      Contract.Requires<ArgumentNullException>(d != null, "argument d must not be null");
      //  if (d == null) throw new ArgumentNullException("d");

      AddDocumentToPriorityNode(d, d.Priority);
    }

    private void AddDocumentToPriorityNode(Document doc, int priority)
    {
      Contract.Requires<ArgumentException>(priority >= 0 && priority < 10, "priority value must be between 0 and 9");
      //if (priority > 9 || priority < 0)
      //    throw new ArgumentException("Priority must be between 0 and 9");

      if (priorityNodes[priority].Value == null)
      {
        --priority;
        if (priority >= 0)
        {
          // check for the next lower priority
          AddDocumentToPriorityNode(doc, priority);
        }
        else // now no priority node exists with the same priority or lower
        // add the new document to the end
        {
          documentList.AddLast(doc);
          priorityNodes[doc.Priority] = documentList.Last;
        }
        return;
      }
      else // a priority node exists
      {
        LinkedListNode<Document> prioNode = priorityNodes[priority];
        if (priority == doc.Priority)
        // priority node with the same priority exists
        {
          documentList.AddAfter(prioNode, doc);

          // set the priority node to the last document with the same priority
          priorityNodes[doc.Priority] = prioNode.Next;
        }
        else // only priority node with a lower priority exists
        {
          // get the first node of the lower priority
          LinkedListNode<Document> firstPrioNode = prioNode;

          while (firstPrioNode.Previous != null &&
             firstPrioNode.Previous.Value.Priority == prioNode.Value.Priority)
          {
            firstPrioNode = prioNode.Previous;
            prioNode = firstPrioNode;
          }

          documentList.AddBefore(firstPrioNode, doc);

          // set the priority node to the new value
          priorityNodes[doc.Priority] = firstPrioNode.Previous;
        }
      }
    }

    public void DisplayAllNodes()
    {
      foreach (Document doc in documentList)
      {
        Console.WriteLine("priority: {0}, title {1}", doc.Priority, doc.Title);
      }
    }

    // returns the document with the highest priority
    // (that's first in the linked list)
    public Document GetDocument()
    {
      Document doc = documentList.First.Value;
      documentList.RemoveFirst();
      return doc;
    }

  }

PriorityDocumentManager

伟德体育官网 24伟德体育官网 25

 class Program
  {
    static void Main()
    {
        PriorityDocumentManager pdm = new PriorityDocumentManager();
        pdm.AddDocument(new Document("one", "Sample", 8));
        pdm.AddDocument(new Document("two", "Sample", 3));
        pdm.AddDocument(new Document("three", "Sample", 4));
        pdm.AddDocument(new Document("four", "Sample", 8));
        pdm.AddDocument(new Document("five", "Sample", 1));
        pdm.AddDocument(new Document("six", "Sample", 9));
        pdm.AddDocument(new Document("seven", "Sample", 1));
        pdm.AddDocument(new Document("eight", "Sample", 1));

        pdm.DisplayAllNodes();

    }
  }

Program

 

6.有体系表

伟德体育官网,SortedList基于键对群集实行排序.

class Program
  {
    static void Main()
    {
      var books = new SortedList<string, string>();
      books.Add("sty", "");
      books.Add("abc", "");
      books.Add("123", "");
      foreach (var item in books.Keys)
      {
          Console.WriteLine(item);
      }

    }
  }

123
abc
sty

 

7.字典

字典:用于在称呼/值对中蕴藏消息,字典的称谓即键无法重复.

伟德体育官网 26

HashTable和Dictionary

1.HashTable大数据量插入数据时索要开销比Dictionary大的多的光阴。

2.for方法遍历HashTable和Dictionary速度最快。

3.在foreach方式遍历时Dictionary遍历速度更加快。

4.HashTable在取值时索要实行类型转变,Dictionary不用做类型调换。

在单线程的时候利用Dictionary越来越好一些,八线程的时候使用HashTable更加好。

 

有序字典SortedList和SortedDictionary

SortedDictionary 泛型类是找寻运算复杂度为 O(log n卡塔尔国 的二叉寻找树,在那之中 n 是字典中的成分数。就那点来讲,它与 SortedList 泛型类相同。那八个类具备近似的靶子模型,而且都抱有
O(log n卡塔尔(قطر‎的查找运算复杂度。那四个类的分别在于内存的选拔甚至插入和移除元素的进程:

  • SortedList 使用的内部存款和储蓄器比 SortedDictionary 少。

  • SortedDictionary 可对未排序的数额举行更加快的插入和移除操作:它的大运复杂度为
    O(log n卡塔尔国,而SortedList 为 O(n)。

  • 万意气风发使用排序数据二次性填充列表,则 SortedList 比 SortedDictionary 快。

8.集

含有不重复元素的汇聚,叫“集”。.NET蕴含2个集。HashSet<T>和SortedSet<T>,它们继续ISet;SortedSet是一个静止集.

ISet提供了Add方法,倘若HashSet中设有那些成分,再度使用Add方法不会抛出非常,重临bool值是还是不是充分

var companyTeams = new HashSet<string>() { "Ferrari", "McLaren", "Mercedes" };
var traditionalTeams = new HashSet<string>() { "Ferrari", "McLaren" };
var privateTeams = new HashSet<string>() { "Red Bull", "Lotus", "Toro Rosso", "Force India", "Sauber" };

if (privateTeams.Add("Williams"))
    Console.WriteLine("Williams added");
if (!companyTeams.Add("McLaren"))
    Console.WriteLine("McLaren was already in this set");

IsSubsetOf方法判断了traditionalTeams集合是否companyTeams的子集
IsSupersetOf方法判断了companyTeams集合是否traditionalTeams的超集(包含它拥有的所有元素,并且多余它的元素)

var companyTeams = new HashSet<string>() { "Ferrari", "McLaren", "Mercedes" };
var traditionalTeams = new HashSet<string>() { "Ferrari", "McLaren" };
var privateTeams = new HashSet<string>() { "Red Bull", "Lotus", "Toro Rosso", "Force India", "Sauber" };

if (traditionalTeams.IsSubsetOf(companyTeams))
{
  Console.WriteLine("traditionalTeams is subset of companyTeams");
}

if (companyTeams.IsSupersetOf(traditionalTeams))
{
   Console.WriteLine("companyTeams is a superset of traditionalTeams");
}

SortedSet的UnionWith方法可以修改这个集合,并且包含传入的集合

var allTeams = new SortedSet<string>(companyTeams);
allTeams.UnionWith(privateTeams);
allTeams.UnionWith(traditionalTeams);

 

9.可查证的集聚

风华正茂经急需记录集结几时增多和删除成分的音信,能够利用ObservableCollection<T>,那几个自个儿是为WPF定制的。

ObservableCollection<T>类用于创制自定义集合,在内部使用List<T>类,重写虚方法RemoveItem和SetItem(卡塔尔(قطر‎方法触发CollectionChanged事件。

伟德体育官网 27伟德体育官网 28

class Program
  {
    static void Main()
    {
      var data = new ObservableCollection<string>();
      data.CollectionChanged += Data_CollectionChanged;
      data.Add("One");
      data.Add("Two");
      data.Insert(1, "Three");
      data.Remove("One");

    }

    static void Data_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
      Console.WriteLine("action: {0}", e.Action.ToString());

      if (e.OldItems != null)
      {
        Console.WriteLine("starting index for old item(s): {0}", e.OldStartingIndex);
        Console.WriteLine("old item(s):");
        foreach (var item in e.OldItems)
        {
          Console.WriteLine(item);
        }
      }
      if (e.NewItems != null)
      {
        Console.WriteLine("starting index for new item(s): {0}", e.NewStartingIndex);
        Console.WriteLine("new item(s): ");
        foreach (var item in e.NewItems)
        {
          Console.WriteLine(item);
        }
      }


      Console.WriteLine();

    }
  }

View Code

Data_CollectionChanged方法选择了NotifyCollectionChangedEventArgs,富含了集聚的调换音信,Action属性给出了是或不是足够或删除大器晚成项的音讯,对于删除的项,会设置OldItems属性,列出删除的项

对于增加的项,会安装NewItems属性,列出丰盛的项。

action: Add
starting index for new item(s): 0
new item(s):
One

action: Add
starting index for new item(s): 1
new item(s):
Two

action: Add
starting index for new item(s): 1
new item(s):
Three

action: Remove
starting index for old item(s): 0
old item(s):
One

 

10.位数组


SparseArray

SparseArray
的选取及实现原理
优势:

  • 防止了大旨数据类型的装箱操作
  • 没有要求额外的构造体,单个成分的蕴藏花费更低
  • 数据量小的情状下,随机拜会的效用更加高

有助益就势必有短处

  • 布署操作须要复制数组,增加和删除功能下跌
  • 数据量庞大时,复制数组费用庞大,gc(卡塔尔(قطر‎花销也壮烈
  • 数据量庞大时,查询效能也会明显回降

BitArray类的方式和质量

下表列出了部分BitArray类的常用属性:

属性 描述
Count 获取包含在BitArray元素的数量
IsReadOnly 获取一个值,指示BitArray是否是只读
Item 获取或设置在所述BitArray的特定位置的比特的值
Length 获取或设置在BitArray元素的数量

下表列出了意气风发部分BitArray类的常用方法:

 

S.N 方法名称及用途
1 public BitArray And( BitArray value ); 
执行对指定BitArray的相应元素在当前BitArray元素的按位与运算
2 public bool Get( int index ); 
获取在所述BitArray的特定位置的比特的值
3 public BitArray Not();
反转当前BitArray所有的位值,使设置为true的元素被更改为false,并设置为false元素更改为true
4 public BitArray Or( BitArray value ); 
在执行对指定BitArray的相应元素在当前BitArray的元素的按位或操作
5 public void Set( int index, bool value ); 
设置在所述BitArray为指定值的特定位置的比特值
6 public void SetAll( bool value ); 
设置在BitArray所有位设置为指定值
7 public BitArray Xor( BitArray value ); 
执行关于对在指定BitArray的相应元素中的当前BitArray的元素按位异或运算

当需求仓库储存位,但不通晓事情发生早先比特数就动用它。您能够透过利用叁个平头索引,它从零初步访问BitArray会集中的项。

伟德体育官网 29伟德体育官网 30

using System;
using System.Collections;

namespace CollectionsApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            //creating two  bit arrays of size 8
            BitArray ba1 = new BitArray(8);
            BitArray ba2 = new BitArray(8);
            byte[] a = { 60 };
            byte[] b = { 13 };

            //storing the values 60, and 13 into the bit arrays
            ba1 = new BitArray(a);
            ba2 = new BitArray(b);

            //content of ba1
            Console.WriteLine("Bit array ba1: 60");
            for (int i = 0; i < ba1.Count; i++)
            {
                Console.Write("{0, -6} ", ba1[i]);
            }
            Console.WriteLine();

            //content of ba2
            Console.WriteLine("Bit array ba2: 13");
            for (int i = 0; i < ba2.Count; i++)
            {
                Console.Write("{0, -6} ", ba2[i]);
            }
            Console.WriteLine();


            BitArray ba3 = new BitArray(8);
            ba3 = ba1.And(ba2);

            //content of ba3
            Console.WriteLine("Bit array ba3 after AND operation: 12");
            for (int i = 0; i < ba3.Count; i++)
            {
                Console.Write("{0, -6} ", ba3[i]);
            }
            Console.WriteLine();

            ba3 = ba1.Or(ba2);
            //content of ba3
            Console.WriteLine("Bit array ba3 after OR operation: 61");
            for (int i = 0; i < ba3.Count; i++)
            {
                Console.Write("{0, -6} ", ba3[i]);
            }
            Console.WriteLine();

            Console.ReadKey();
        }
    }
}

View Code

让咱们编写翻译和周转方面包车型客车顺序,那将生出以下结果:

Bit array ba1: 60 
False False True True True True False False 
Bit array ba2: 13
True False True True False False False False 
Bit array ba3 after AND operation: 12
False False True True False False False False 
Bit array ba3 after OR operation: 61
True False True True False False False False 

一、前言

笔者最近在做三个类型,项目中为了进步吞吐量,使用了音讯队列,中间达成了延续祖宗门户开销情势,在生养消费者方式中供给有叁个集聚,来积存生产者所临盆的货色,小编使用了最普及的List<T>聚拢类型。

鉴于生产者线程有众五个,消费者线程也是有那个个,所以不可幸免的就生出了线程同步的主题素材。带头作者是行使lock首要字,实行线程同步,不过质量实际不是特地出彩,然后有网民说能够应用SynchronizedList<T>来替代使用List<T>直达到规定的分数线程安全的指标。于是作者就替换来了SynchronizedList<T>,不过开采质量依旧不好,于是查看了SynchronizedList<T>的源代码,发现它正是大约的在List<T>提供的API的底蕴上加了lock,所以品质基本与小编完成方式八九不离十。

最后小编找到了消除的方案,使用ConcurrentBag<T>类来兑现,质量有不小的改动,于是小编查阅了ConcurrentBag<T>的源代码,达成充足小巧,特此在此记录一下。

HashSet

对于 HashSet 中保存的目的,请当心科学重写其 equals 和 hashCode
方法,以保障放入的靶子的唯一性。那三个措施是比较根本的,希望大家在事后的用渡进程中需求留意一下。

伟德体育官网 31

image.png

BitVector32

提供了三个简单易行构造,该协会以32人内存存款和储蓄布尔和小数值

对于个中选择的布尔值和小整数,BitVector32 比 BitArray 更有效。 BitArray 能够按须要特别地增添,但它有内部存款和储蓄器和品质方面包车型地铁系统开荒,这是类实例所必要的。 相比较之下,BitVector32 只行使 三14人。

BitVector32 构造能够设置成满含小大背头的若干节或包括布尔值的多少位标记,但无法同期饱含两个。BitVector32.Section 是 BitVector32 中的窗口,且由细小数量的连接位结合,三番三次位能够富含 CreateSection 中内定的最大值。 比方,带有最大值 1 的节只由一个位构成,而带有最大值 5
的节由几个位构成。 能够创立带有最大值 1 的 BitVector32.Section 作为布尔值,进而使您能够在同后生可畏 BitVector32 中存款和储蓄整数和布尔值。

BitVector32 既可以够安装为节,也得以安装为位标记,分别有成员能够采用于那二种状态。 例如,BitVector32.Item 属性是当作节设置的 BitVector32 的索引器,而 BitVector32.Item 属性是当作位标识设置的BitVector32 的索引器。 CreateMask 创设大器晚成二种屏蔽,那些屏蔽可用来访谈作为位标记设置的 BitVector32 中的单个位。

在作为节设置的 BitVector32 上采纳屏蔽或许会造成意外的结果。

伟德体育官网 32伟德体育官网 33

using System;
using System.Collections.Specialized;


public class SamplesBitVector32  {

   public static void Main()  {

      // Creates and initializes a BitVector32 with all bit flags set to FALSE.
      BitVector32 myBV = new BitVector32( 0 );

      // Creates masks to isolate each of the first five bit flags.
      int myBit1 = BitVector32.CreateMask();
      int myBit2 = BitVector32.CreateMask( myBit1 );
      int myBit3 = BitVector32.CreateMask( myBit2 );
      int myBit4 = BitVector32.CreateMask( myBit3 );
      int myBit5 = BitVector32.CreateMask( myBit4 );

      // Sets the alternating bits to TRUE.
      Console.WriteLine( "Setting alternating bits to TRUE:" );
      Console.WriteLine( "   Initial:         {0}", myBV.ToString() );
      myBV[myBit1] = true;
      Console.WriteLine( "   myBit1 = TRUE:   {0}", myBV.ToString() );
      myBV[myBit3] = true;
      Console.WriteLine( "   myBit3 = TRUE:   {0}", myBV.ToString() );
      myBV[myBit5] = true;
      Console.WriteLine( "   myBit5 = TRUE:   {0}", myBV.ToString() );

   }

}

/*
This code produces the following output.

Setting alternating bits to TRUE:
   Initial:         BitVector32{00000000000000000000000000000000}
   myBit1 = TRUE:   BitVector32{00000000000000000000000000000001}
   myBit3 = TRUE:   BitVector32{00000000000000000000000000000101}
   myBit5 = TRUE:   BitVector32{00000000000000000000000000010101}


*/
BitVector用作节集合

using System;
using System.Collections.Specialized;


public class SamplesBitVector32  {

   public static void Main()  {

      // Creates and initializes a BitVector32.
      BitVector32 myBV = new BitVector32( 0 );

      // Creates four sections in the BitVector32 with maximum values 6, 3, 1, and 15.
      // mySect3, which uses exactly one bit, can also be used as a bit flag.
      BitVector32.Section mySect1 = BitVector32.CreateSection( 6 );
      BitVector32.Section mySect2 = BitVector32.CreateSection( 3, mySect1 );
      BitVector32.Section mySect3 = BitVector32.CreateSection( 1, mySect2 );
      BitVector32.Section mySect4 = BitVector32.CreateSection( 15, mySect3 );

      // Displays the values of the sections.
      Console.WriteLine( "Initial values:" );
      Console.WriteLine( "tmySect1: {0}", myBV[mySect1] );
      Console.WriteLine( "tmySect2: {0}", myBV[mySect2] );
      Console.WriteLine( "tmySect3: {0}", myBV[mySect3] );
      Console.WriteLine( "tmySect4: {0}", myBV[mySect4] );

      // Sets each section to a new value and displays the value of the BitVector32 at each step.
      Console.WriteLine( "Changing the values of each section:" );
      Console.WriteLine( "tInitial:    t{0}", myBV.ToString() );
      myBV[mySect1] = 5;
      Console.WriteLine( "tmySect1 = 5:t{0}", myBV.ToString() );
      myBV[mySect2] = 3;
      Console.WriteLine( "tmySect2 = 3:t{0}", myBV.ToString() );
      myBV[mySect3] = 1;
      Console.WriteLine( "tmySect3 = 1:t{0}", myBV.ToString() );
      myBV[mySect4] = 9;
      Console.WriteLine( "tmySect4 = 9:t{0}", myBV.ToString() );

      // Displays the values of the sections.
      Console.WriteLine( "New values:" );
      Console.WriteLine( "tmySect1: {0}", myBV[mySect1] );
      Console.WriteLine( "tmySect2: {0}", myBV[mySect2] );
      Console.WriteLine( "tmySect3: {0}", myBV[mySect3] );
      Console.WriteLine( "tmySect4: {0}", myBV[mySect4] );

   }

}

View Code

伟德体育官网 34伟德体育官网 35

/*
This code produces the following output.

Initial values:
        mySect1: 0
        mySect2: 0
        mySect3: 0
        mySect4: 0
Changing the values of each section:
        Initial:        BitVector32{00000000000000000000000000000000}
        mySect1 = 5:    BitVector32{00000000000000000000000000000101}
        mySect2 = 3:    BitVector32{00000000000000000000000000011101}
        mySect3 = 1:    BitVector32{00000000000000000000000000111101}
        mySect4 = 9:    BitVector32{00000000000000000000001001111101}
New values:
        mySect1: 5
        mySect2: 3
        mySect3: 1
        mySect4: 9

*/

View Code

 

11.不改变的聚焦

Net提供的不可变群集

ImmutableStack<int> a1 = ImmutableStack<int>.Empty;
ImmutableStack<int> a2 = a1.Push(10);
ImmutableStack<int> a3 = a2.Push(20);
ImmutableStack<int> a4 = a3.Push(30);
ImmutableStack<int> iv3 = a4.Pop(); 

使用Net不可变列表集合有好几要小心的是,当大家Push值时要重新赋值给原变量才正确,因为push后会生成三个新指标,原a1只是旧值:

ImmutableStack<int> a1 = ImmutableStack<int>.Empty;
a1.Push(10); //不正确,a1仍是空值值,push会生成新的栈。
a1 = a1.Push(10); //需要将新栈重新赋值给a1

NET提供的常用数据结构

1.ImmutableStack
2.ImmutableQueue
3.ImmutableList
4.ImmutableHashSet
5.ImmutableSortedSet
6.ImmutableDictionary<K, V>
7.ImmutableSortedDictionary<K, V>

不可变优点

1.凑合分享安全,从不被转移
2.做客集适合时宜,无需锁会集(线程安全)
3.改换集合不思量旧集结被改成
4.书写更简洁,函数式风格。 var list =
ImmutableList.Empty.Add(10卡塔尔国.Add(20卡塔尔.Add(30卡塔尔(英语:State of Qatar);
5.保障数据完整性,安全性

不可变对象劣势

不可变本人的优点正是缺点,当每回对象/群集操作都会回来个新值。而旧值依然会保留后生可畏段时间,那会使内装有一点都不小开销,也会给GC产生回笼肩负,质量也比可变会集差的多。

伟德体育官网 36

 

12.并发集结

线程安全的汇集可防守四个线程以相互作用冲突的诀要访谈集合

.NET 的System.Collections.Concurrent提供了多少个安全的类和成效:

说明
BlockingCollection<T>
ConcurrentBag<T>
ConcurrentDictionary<TKey, TValue>
ConcurrentQueue<T>
ConcurrentStack<T>
OrderablePartitioner<TSource>
Partitioner
Partitioner<TSource>

1卡塔尔(قطر‎创立管道

将这一个并发集合类用于管道,二个任务向叁个会集类写入一些内容,同一时间另一个职分从该群集中读取内容

身体力行中三个职责产生二个管道.
第3个管道,
第1等第的职责读取文件名,加多到行列,那一个职务运维同期,
第2阶段的职责已经最早从队列中读取文件名并加载它们的顺序,结果被写入另贰个队列。
第3品级同期起步,读取并拍卖第3个类别的原委,结果被写入四个字典。

第3品级完结,並且内容已被最后处理,字典得到完全结果时,下大器晚成阶段才起来。
第4等级从字典中读取内容,转换数据,然后写入队列中
第5品级在项中丰裕颜色新闻,然后把它们增进到另一个队列中,最后三个等第呈现音信。
第4到第6品级也得以并发运营.

伟德体育官网 37伟德体育官网 38

class Program
  {
    static void Main(string[] args)
    {
      StartPipeline();
      Console.ReadLine();
    }

    private static async void StartPipeline()
    {
      var fileNames = new BlockingCollection<string>();
      var lines = new BlockingCollection<string>();
      var words = new ConcurrentDictionary<string, int>();
      var items = new BlockingCollection<Info>();
      var coloredItems = new BlockingCollection<Info>();

      Task t1 = PipelineStages.ReadFilenamesAsync(@"../../..", fileNames);
      ConsoleHelper.WriteLine("started stage 1");
      Task t2 = PipelineStages.LoadContentAsync(fileNames, lines);
      ConsoleHelper.WriteLine("started stage 2");
      Task t3 = PipelineStages.ProcessContentAsync(lines, words);
      await Task.WhenAll(t1, t2, t3);
      ConsoleHelper.WriteLine("stages 1, 2, 3 completed");

      Task t4 = PipelineStages.TransferContentAsync(words, items);
      Task t5 = PipelineStages.AddColorAsync(items, coloredItems);
      Task t6 = PipelineStages.ShowContentAsync(coloredItems);
      ConsoleHelper.WriteLine("stages 4, 5, 6 started");

      await Task.WhenAll(t4, t5, t6);

      ConsoleHelper.WriteLine("all stages finished");
    }
  }

Program

伟德体育官网 39伟德体育官网 40

public class ConsoleHelper
  {
    private static object syncOutput = new object();

    public static void WriteLine(string message)
    {
      lock (syncOutput)
      {
        Console.WriteLine(message);
      }
    }

    public static void WriteLine(string message, string color)
    {
      lock (syncOutput)
      {
        Console.ForegroundColor = (ConsoleColor)Enum.Parse(typeof(ConsoleColor), color);
        Console.WriteLine(message);
        Console.ResetColor();
      }
    }
  }

ConsoleHelper

伟德体育官网 41伟德体育官网 42

public static class PipelineStages
  {
    public static Task ReadFilenamesAsync(string path, BlockingCollection<string> output)
    {
      return Task.Run(() =>
        {
          foreach (string filename in Directory.EnumerateFiles(path, "*.cs", SearchOption.AllDirectories))
          {
            output.Add(filename);
            ConsoleHelper.WriteLine(string.Format("stage 1: added {0}", filename));
          }
          output.CompleteAdding();
        });
    }

    public static async Task LoadContentAsync(BlockingCollection<string> input, BlockingCollection<string> output)
    {
      foreach (var filename in input.GetConsumingEnumerable())
      {
        using (FileStream stream = File.OpenRead(filename))
        {
          var reader = new StreamReader(stream);
          string line = null;
          while ((line = await reader.ReadLineAsync()) != null)
          {
            output.Add(line);
            ConsoleHelper.WriteLine(string.Format("stage 2: added {0}", line));
          }
        }
      }
      output.CompleteAdding();
    }

    public static Task ProcessContentAsync(BlockingCollection<string> input, ConcurrentDictionary<string, int> output)
    {
      return Task.Run(() =>
        {
          foreach (var line in input.GetConsumingEnumerable())
          {
            string[] words = line.Split(' ', ';', 't', '{', '}', '(', ')', ':', ',', '"');
            foreach (var word in words.Where(w => !string.IsNullOrEmpty(w)))
            {
              output.AddOrIncrementValue(word);
              ConsoleHelper.WriteLine(string.Format("stage 3: added {0}", word));
            }
          }
        });
    }

    public static Task TransferContentAsync(ConcurrentDictionary<string, int> input, BlockingCollection<Info> output)
    {
      return Task.Run(() =>
        {
          foreach (var word in input.Keys)
          {
            int value;
            if (input.TryGetValue(word, out value))
            {
              var info = new Info { Word = word, Count = value };
              output.Add(info);
              ConsoleHelper.WriteLine(string.Format("stage 4: added {0}", info));
            }
          }
          output.CompleteAdding();
        });
    }

    public static Task AddColorAsync(BlockingCollection<Info> input, BlockingCollection<Info> output)
    {
      return Task.Run(() =>
        {
          foreach (var item in input.GetConsumingEnumerable())
          {
            if (item.Count > 40)
            {
              item.Color = "Red";
            }
            else if (item.Count > 20)
            {
              item.Color = "Yellow";
            }
            else
            {
              item.Color = "Green";
            }
            output.Add(item);
            ConsoleHelper.WriteLine(string.Format("stage 5: added color {1} to {0}", item, item.Color));
          }
          output.CompleteAdding();
        });
    }

    public static Task ShowContentAsync(BlockingCollection<Info> input)
    {
      return Task.Run(() =>
        {
          foreach (var item in input.GetConsumingEnumerable())
          {
            ConsoleHelper.WriteLine(string.Format("stage 6: {0}", item), item.Color);
          }
        });
    }
  }

PipelineStages

 

2)使用BlockingCollection

第1品级的ReadFilenamesAsync方法,达成了迭代目录文件名。在产生文件名增加后调用output.CompleteAdding(卡塔尔(英语:State of Qatar);用以文告全部读取器不再等待集结中任何附加的项.若无调用的话,循环中读取器会加上等待更多的项.

伟德体育官网 43伟德体育官网 44

public static Task ReadFilenamesAsync(string path, BlockingCollection<string> output)
    {
      return Task.Run(() =>
        {
          foreach (string filename in Directory.EnumerateFiles(path, "*.cs", SearchOption.AllDirectories))
          {
            output.Add(filename);
            ConsoleHelper.WriteLine(string.Format("stage 1: added {0}", filename));
          }
          output.CompleteAdding();
        });
    }

ReadFilenamesAsync

下风华正茂阶段读取文件并将器内容增多到另一个相会中,由LoadContentAsync方法成功,该措施应用了输入集结传递的公文名,张开文件,把文件中的全数行增多到输出的聚聚焦。在循环中用输入堵塞集合调用GetConsumingEnumerable(卡塔尔(قطر‎方法,以迭代各个,不行使也是能够的,但是值会迭代当前事态的聚众。不会迭代以往加多的项。

黄金年代旦在填写集结的同不经常候,使用读取器读取集合,则供给利用GetConsumingEnumerable(卡塔尔国方法赢得窒碍集合的枚举器,实际不是直接迭代会集

伟德体育官网 45伟德体育官网 46

public static async Task LoadContentAsync(BlockingCollection<string> input, BlockingCollection<string> output)
    {
      foreach (var filename in input.GetConsumingEnumerable())
      {
        using (FileStream stream = File.OpenRead(filename))
        {
          var reader = new StreamReader(stream);
          string line = null;
          while ((line = await reader.ReadLineAsync()) != null)
          {
            output.Add(line);
            ConsoleHelper.WriteLine(string.Format("stage 2: added {0}", line));
          }
        }
      }
      output.CompleteAdding();
    }

LoadContentAsync

 

3)使用ConcurrentDictionary

伟德体育官网 47

伟德体育官网 48伟德体育官网 49

public static Task ProcessContentAsync(BlockingCollection<string> input, ConcurrentDictionary<string, int> output)
    {
      return Task.Run(() =>
        {
          foreach (var line in input.GetConsumingEnumerable())
          {
            string[] words = line.Split(' ', ';', 't', '{', '}', '(', ')', ':', ',', '"');
            foreach (var word in words.Where(w => !string.IsNullOrEmpty(w)))
            {
              output.AddOrIncrementValue(word);
              ConsoleHelper.WriteLine(string.Format("stage 3: added {0}", word));
            }
          }
        });
    }

ProcessContentAsync

伟德体育官网 50

伟德体育官网 51伟德体育官网 52

public static class ConcurrentDictionaryExtension
  {
    public static void AddOrIncrementValue(this ConcurrentDictionary<string, int> dict, string key)
    {
      bool success = false;
      while (!success)
      {
        int value;
        if (dict.TryGetValue(key, out value))
        {
          if (dict.TryUpdate(key, value + 1, value))
          {
            success = true;
          }
        }
        else
        {
          if (dict.TryAdd(key, 1))
          {
            success = true;
          }
        }
      }
    }
  }

ConcurrentDictionaryExtension

伟德体育官网 53

在成就第一个级次后,第4到6品级也得以互相运营,TransferContentAsync从字典中获取数据,举办类型转换,输出到BlockingCollection<string>中

伟德体育官网 54伟德体育官网 55

 public static Task ProcessContentAsync(BlockingCollection<string> input, ConcurrentDictionary<string, int> output)
    {
      return Task.Run(() =>
        {
          foreach (var line in input.GetConsumingEnumerable())
          {
            string[] words = line.Split(' ', ';', 't', '{', '}', '(', ')', ':', ',', '"');
            foreach (var word in words.Where(w => !string.IsNullOrEmpty(w)))
            {
              output.AddOrIncrementValue(word);
              ConsoleHelper.WriteLine(string.Format("stage 3: added {0}", word));
            }
          }
        });
    }

    public static Task TransferContentAsync(ConcurrentDictionary<string, int> input, BlockingCollection<Info> output)
    {
      return Task.Run(() =>
        {
          foreach (var word in input.Keys)
          {
            int value;
            if (input.TryGetValue(word, out value))
            {
              var info = new Info { Word = word, Count = value };
              output.Add(info);
              ConsoleHelper.WriteLine(string.Format("stage 4: added {0}", info));
            }
          }
          output.CompleteAdding();
        });
    }

    public static Task AddColorAsync(BlockingCollection<Info> input, BlockingCollection<Info> output)
    {
      return Task.Run(() =>
        {
          foreach (var item in input.GetConsumingEnumerable())
          {
            if (item.Count > 40)
            {
              item.Color = "Red";
            }
            else if (item.Count > 20)
            {
              item.Color = "Yellow";
            }
            else
            {
              item.Color = "Green";
            }
            output.Add(item);
            ConsoleHelper.WriteLine(string.Format("stage 5: added color {1} to {0}", item, item.Color));
          }
          output.CompleteAdding();
        });
    }

    public static Task ShowContentAsync(BlockingCollection<Info> input)
    {
      return Task.Run(() =>
        {
          foreach (var item in input.GetConsumingEnumerable())
          {
            ConsoleHelper.WriteLine(string.Format("stage 6: {0}", item), item.Color);
          }
        });
    }

View Code

 

 

13.性能

聚拢的诀窍经常有品质提醒,给出大写O记录操作时间。

伟德体育官网 56

O(1卡塔尔国表示无论是群集中有多少多少项,这几个操作要求的时间都不改变。
O(n卡塔尔国代表对此会集试行一个操作必要的风云在最坏景况时是N.
O(log n卡塔尔(英语:State of Qatar)表示操作供给的年月随集结中元素的增添而扩展

伟德体育官网 57

二、ConcurrentBag类

ConcurrentBag<T>实现了IProducerConsumerCollection<T>接口,该接口主要用于临盆者购买者方式下,可以知道该类基本就是为分娩消费者形式定制的。然后还达成了常规的IReadOnlyCollection<T>类,达成了此类就要求落实IEnumerable<T>、IEnumerable、 ICollection类。

ConcurrentBag<T>对外提供的不二诀窍未有List<T>那么多,然而相仿有Enumerable落到实处的扩充方法。类自身提供的点子如下所示。

名称 说明
Add 将对象添加到 ConcurrentBag 中。
CopyTo 从指定数组索引开始,将 ConcurrentBag 元素复制到现有的一维 Array 中。
Equals(Object) 确定指定的 Object 是否等于当前的 Object。 (继承自 Object。)
Finalize 允许对象在“垃圾回收”回收之前尝试释放资源并执行其他清理操作。 (继承自 Object。)
GetEnumerator 返回循环访问 ConcurrentBag 的枚举器。
GetHashCode 用作特定类型的哈希函数。 (继承自 Object。)
GetType 获取当前实例的 Type。 (继承自 Object。)
MemberwiseClone 创建当前 Object 的浅表副本。 (继承自 Object。)
ToArray 将 ConcurrentBag 元素复制到新数组。
ToString 返回表示当前对象的字符串。 (继承自 Object。)
TryPeek 尝试从 ConcurrentBag 返回一个对象但不移除该对象。
TryTake 尝试从 ConcurrentBag 中移除并返回对象。

Hashtable

HashMap和HashTab的异同

1.HashTable 依据 Dictionary 类,而 HashMap 是依据AbstractMap。Dictionary 是其他可将键映射到相应值的类的肤浅父类,而
AbstractMap 是基于 Map
接口的完成,它以最大限度地压缩实现此接口所需的劳作。

2.HashMap 的 key 和 value 都同意为 null,而 Hashtable 的 key 和 value
都不容许为 null。HashMap 遭受 key 为 null 的时候,调用 putForNullKey
方法开展管理,而对 value 未有拍卖;Hashtable遭受 null,直接重返NullPointerException。

3.Hashtable 主意是风姿洒脱道,而HashMap则不是。大家得以看一下源码,Hashtable
中的大约具有的 public 的艺术都以 synchronized
的,而有些措施也是在里边通过 synchronized
代码块来落到实处。所以有人平时都提出意气风发旦是关联到十六线程同步时采用HashTable,未有提到就利用 HashMap,可是在 Collections
类中设有一个静态方法:synchronizedMap(卡塔尔国,该办法创制了三个线程安全的
Map 对象,并把它看作叁个卷入的靶子来回到。

非泛型类集结

泛型集结类是在.NET2.0的时候出来的,也正是说在1.0的时候是未曾这么方便的事物的。现在基本上大家早已不接收这几个集合类了,除非在做一些和老代码保持非凡的职业的时候。来拜会1.0时日的.NET程序员们都有哪些集合类能够用。

ArraryList后来被List<T>替代。

HashTable 后来被Dictionary<TKey,TValue>替代。 
Queue 后来被Queue<T>替代。 
SortedList 后来被SortedList<T>替代。 
Stack 后来被Stack<T>替代。

三、 ConcurrentBag线程安全完毕原理

LinkedHashMap

LinkedHashMap是Hash表和链表的兑现,而且依据着双向链表保险了迭代种种是插入的种种
实际上 LinkedHashMap 大约和 HashMap
同样:从技能上来讲,不一样的是它定义了四个 Entry<K,V> header,这几个header 不是坐落于 Table 里,它是额外独立出来的。LinkedHashMap 通过再三再四hashMap 中的 Entry<K,V>,并增添七个属性 Entry<K,V>
before,after,和 header
结合起来组成二个双向链表,来促成按插入顺序或访谈顺序排序。
HashMap,LinkedHashMap,TreeMap的区别

线程安全的集合类

ConcurrentQueue 线程安全版本的Queue 
ConcurrentStack线程安全版本的Stack 
ConcurrentBag线程安全的目的集结 
ConcurrentDictionary线程安全的Dictionary 
BlockingCollection

 

1. ConcurrentBag的民用字段

ConcurrentBag线程安全落成重视是经过它的数目存款和储蓄的组织和细颗粒度的锁。

   public class ConcurrentBag<T> : IProducerConsumerCollection<T>, IReadOnlyCollection<T>
    {
        // ThreadLocalList对象包含每个线程的数据
        ThreadLocal<ThreadLocalList> m_locals;

        // 这个头指针和尾指针指向中的第一个和最后一个本地列表,这些本地列表分散在不同线程中
        // 允许在线程局部对象上枚举
        volatile ThreadLocalList m_headList, m_tailList;

        // 这个标志是告知操作线程必须同步操作
        // 在GlobalListsLock 锁中 设置
        bool m_needSync;

}

首要推荐我们来看它注解的民用字段,个中必要小心的是汇集的数量是寄放在在ThreadLocal线程本地存款和储蓄中的。也即是说访谈它的每种线程会维护三个友好的见面数据列表,二个群集中的数据只怕会寄存在不一样线程的本土存款和储蓄空间中,所以只要线程访谈自身本地存款和储蓄的对象,那么是寻常的,那正是贯彻线程安全的率先层,运用线程本地存款和储蓄数据

下一场能够看看ThreadLocalList m_headList, m_tailList;其一是寄存在着地点列表对象的头指针和尾指针,通过那多少个指针,我们就足以因而遍历的方法来寻访具备地方列表。它选择volatile修饰,不容许线程举办地面缓存,种种线程的读写都以直接操作在分享内部存款和储蓄器上,那就保证了变量始终富有意气风发致性。任何线程在别的时刻张开读写操作均是时尚值。对于volatile修饰符,感谢自家是工程师建议描述不当。

末段又定义了四个注解,那些标识告知操作线程必须举行同步操作,那是兑现了三个细颗粒度的锁,因为独有在多少个条件满足的动静下才供给张开线程同步。

LinkedHashSet

  • LinkedHashSet 是 Set
    的三个现实落实,其尊崇着三个运作于具有规行矩步的再度链接列表。此链接列表定义了迭代相继,该迭代顺序可为插入顺序或是访谈顺序。
  • LinkedHashSet 世襲与 HashSet,何况其里面是透过 LinkedHashMap
    来落到实处的。有一点近似于大家前边说的LinkedHashMap 此中间是依照 Hashmap
    完成平等,可是依然有一丢丢差其他(具体的差别大家可以团结去思量一下)。
  • 若果大家需求迭代的逐个为插入顺序可能访问顺序,那么 LinkedHashSet
    是亟需您首先寻思的。

2. 用以数据存款和储蓄的TrehadLocalList类

接下去大家来看一下ThreadLocalList类的结构,该类正是实际上存款和储蓄了数额的岗位。实际上它是选用双向链表这种组织进行多少存款和储蓄。

[Serializable]
// 构造了双向链表的节点
internal class Node
{
    public Node(T value)
    {
        m_value = value;
    }
    public readonly T m_value;
    public Node m_next;
    public Node m_prev;
}

/// <summary>
/// 集合操作类型
/// </summary>
internal enum ListOperation
{
    None,
    Add,
    Take
};

/// <summary>
/// 线程锁定的类
/// </summary>
internal class ThreadLocalList
{
    // 双向链表的头结点 如果为null那么表示链表为空
    internal volatile Node m_head;

    // 双向链表的尾节点
    private volatile Node m_tail;

    // 定义当前对List进行操作的种类 
    // 与前面的 ListOperation 相对应
    internal volatile int m_currentOp;

    // 这个列表元素的计数
    private int m_count;

    // The stealing count
    // 这个不是特别理解 好像是在本地列表中 删除某个Node 以后的计数
    internal int m_stealCount;

    // 下一个列表 可能会在其它线程中
    internal volatile ThreadLocalList m_nextList;

    // 设定锁定是否已进行
    internal bool m_lockTaken;

    // The owner thread for this list
    internal Thread m_ownerThread;

    // 列表的版本,只有当列表从空变为非空统计是底层
    internal volatile int m_version;

    /// <summary>
    /// ThreadLocalList 构造器
    /// </summary>
    /// <param name="ownerThread">拥有这个集合的线程</param>
    internal ThreadLocalList(Thread ownerThread)
    {
        m_ownerThread = ownerThread;
    }
    /// <summary>
    /// 添加一个新的item到链表首部
    /// </summary>
    /// <param name="item">The item to add.</param>
    /// <param name="updateCount">是否更新计数.</param>
    internal void Add(T item, bool updateCount)
    {
        checked
        {
            m_count++;
        }
        Node node = new Node(item);
        if (m_head == null)
        {
            Debug.Assert(m_tail == null);
            m_head = node;
            m_tail = node;
            m_version++; // 因为进行初始化了,所以将空状态改为非空状态
        }
        else
        {
            // 使用头插法 将新的元素插入链表
            node.m_next = m_head;
            m_head.m_prev = node;
            m_head = node;
        }
        if (updateCount) // 更新计数以避免此添加同步时溢出
        {
            m_count = m_count - m_stealCount;
            m_stealCount = 0;
        }
    }

    /// <summary>
    /// 从列表的头部删除一个item
    /// </summary>
    /// <param name="result">The removed item</param>
    internal void Remove(out T result)
    {
        // 双向链表删除头结点数据的流程
        Debug.Assert(m_head != null);
        Node head = m_head;
        m_head = m_head.m_next;
        if (m_head != null)
        {
            m_head.m_prev = null;
        }
        else
        {
            m_tail = null;
        }
        m_count--;
        result = head.m_value;

    }

    /// <summary>
    /// 返回列表头部的元素
    /// </summary>
    /// <param name="result">the peeked item</param>
    /// <returns>True if succeeded, false otherwise</returns>
    internal bool Peek(out T result)
    {
        Node head = m_head;
        if (head != null)
        {
            result = head.m_value;
            return true;
        }
        result = default(T);
        return false;
    }

    /// <summary>
    /// 从列表的尾部获取一个item
    /// </summary>
    /// <param name="result">the removed item</param>
    /// <param name="remove">remove or peek flag</param>
    internal void Steal(out T result, bool remove)
    {
        Node tail = m_tail;
        Debug.Assert(tail != null);
        if (remove) // Take operation
        {
            m_tail = m_tail.m_prev;
            if (m_tail != null)
            {
                m_tail.m_next = null;
            }
            else
            {
                m_head = null;
            }
            // Increment the steal count
            m_stealCount++;
        }
        result = tail.m_value;
    }


    /// <summary>
    /// 获取总计列表计数, 它不是线程安全的, 如果同时调用它, 则可能提供不正确的计数
    /// </summary>
    internal int Count
    {
        get
        {
            return m_count - m_stealCount;
        }
    }
}

从地点的代码中我们能够更进一层证实早前的视角,正是ConcurentBag<T>在二个线程中存放数据时,使用的是双向链表ThreadLocalList得以达成了风流罗曼蒂克组对链表增加和删除改查的诀窍。

ArrayList

底层采取Object[]数组来贯彻
ArrayList 能够领悟为动态数组,用 MSDN 中的说法,就是 Array
的良莠不齐版本。与 Java 中的数组相比较,它的体量能动态拉长。ArrayList 是 List
接口的可变数组的落到实处。实现了富有可选列表操作,并允许包蕴 null
在内的保有因素。除了落到实处 List
接口外,此类还提供部分主意来操作内部用来积存列表的数组的轻重。(此类大致上同生龙活虎Vector 类,除了此类是不一同的。)

3. ConcurrentBag兑现新扩展成分

接下去大家看生龙活虎看ConcurentBag<T>是哪些新扩展成分的。

/// <summary>
/// 尝试获取无主列表,无主列表是指线程已经被暂停或者终止,但是集合中的部分数据还存储在那里
/// 这是避免内存泄漏的方法
/// </summary>
/// <returns></returns>
private ThreadLocalList GetUnownedList()
{
    //此时必须持有全局锁
    Contract.Assert(Monitor.IsEntered(GlobalListsLock));

    // 从头线程列表开始枚举 找到那些已经被关闭的线程
    // 将它所在的列表对象 返回
    ThreadLocalList currentList = m_headList;
    while (currentList != null)
    {
        if (currentList.m_ownerThread.ThreadState == System.Threading.ThreadState.Stopped)
        {
            currentList.m_ownerThread = Thread.CurrentThread; // the caller should acquire a lock to make this line thread safe
            return currentList;
        }
        currentList = currentList.m_nextList;
    }
    return null;
}
/// <summary>
/// 本地帮助方法,通过线程对象检索线程线程本地列表
/// </summary>
/// <param name="forceCreate">如果列表不存在,那么创建新列表</param>
/// <returns>The local list object</returns>
private ThreadLocalList GetThreadList(bool forceCreate)
{
    ThreadLocalList list = m_locals.Value;

    if (list != null)
    {
        return list;
    }
    else if (forceCreate)
    {
        // 获取用于更新操作的 m_tailList 锁
        lock (GlobalListsLock)
        {
            // 如果头列表等于空,那么说明集合中还没有元素
            // 直接创建一个新的
            if (m_headList == null)
            {
                list = new ThreadLocalList(Thread.CurrentThread);
                m_headList = list;
                m_tailList = list;
            }
            else
            {
               // ConcurrentBag内的数据是以双向链表的形式分散存储在各个线程的本地区域中
                // 通过下面这个方法 可以找到那些存储有数据 但是已经被停止的线程
                // 然后将已停止线程的数据 移交到当前线程管理
                list = GetUnownedList();
                // 如果没有 那么就新建一个列表 然后更新尾指针的位置
                if (list == null)
                {
                    list = new ThreadLocalList(Thread.CurrentThread);
                    m_tailList.m_nextList = list;
                    m_tailList = list;
                }
            }
            m_locals.Value = list;
        }
    }
    else
    {
        return null;
    }
    Debug.Assert(list != null);
    return list;
}
/// <summary>
/// Adds an object to the <see cref="ConcurrentBag{T}"/>.
/// </summary>
/// <param name="item">The object to be added to the
/// <see cref="ConcurrentBag{T}"/>. The value can be a null reference
/// (Nothing in Visual Basic) for reference types.</param>
public void Add(T item)
{
    // 获取该线程的本地列表, 如果此线程不存在, 则创建一个新列表 (第一次调用 add)
    ThreadLocalList list = GetThreadList(true);
    // 实际的数据添加操作 在AddInternal中执行
    AddInternal(list, item);
}

/// <summary>
/// </summary>
/// <param name="list"></param>
/// <param name="item"></param>
private void AddInternal(ThreadLocalList list, T item)
{
    bool lockTaken = false;
    try
    {
        #pragma warning disable 0420
        Interlocked.Exchange(ref list.m_currentOp, (int)ListOperation.Add);
        #pragma warning restore 0420
        // 同步案例:
        // 如果列表计数小于两个, 因为是双向链表的关系 为了避免与任何窃取线程发生冲突 必须获取锁
        // 如果设置了 m_needSync, 这意味着有一个线程需要冻结包 也必须获取锁
        if (list.Count < 2 || m_needSync)
        {
            // 将其重置为None 以避免与窃取线程的死锁
            list.m_currentOp = (int)ListOperation.None;
            // 锁定当前对象
            Monitor.Enter(list, ref lockTaken);
        }
        // 调用 ThreadLocalList.Add方法 将数据添加到双向链表中
        // 如果已经锁定 那么说明线程安全  可以更新Count 计数
        list.Add(item, lockTaken);
    }
    finally
    {
        list.m_currentOp = (int)ListOperation.None;
        if (lockTaken)
        {
            Monitor.Exit(list);
        }
    }
}

从地点代码中,大家能够很清楚的精晓Add()办法是何许运维的,此中的重大正是GetThreadList()情势,通过该方式可以取安妥前线程的数量存款和储蓄列表对象,倘诺不设有多少存款和储蓄列表,它会活动成立也许通过GetUnownedList()方式来搜寻那几个被截至可是还蕴藏有多少列表的线程,然后将数据列表再次来到给当下线程中,幸免了内部存款和储蓄器泄漏。

在数额拉长的经过中,达成了细颗粒度的lock贰只锁,所以质量会异常高。删除和别的操作与新扩大相近,本文不再赘言。

LinkedList

LinkedList 是根据链表架构完结,所以在类中包蕴了 first 和 last
五个指针(Node卡塔尔。Node
中饱含了上叁个节点和下三个节点的援引,那样就构成了双向的链表。每种 Node
只好知道自个儿的前多少个节点和后多少个节点,但对此链表来讲,那早已足够了。

4. ConcurrentBag 怎样贯彻迭代器格局

看完上边的代码后,笔者很愕然ConcurrentBag<T>是如何落到实处IEnumerator来促成迭代访谈的,因为ConcurrentBag<T>是通过分散在分裂线程中的ThreadLocalList来囤积数据的,那么在促成迭代器形式时,进度会相比复杂。

末端再查看了源码之后,发掘ConcurrentBag<T>为了完成迭代器格局,将分在分歧线程中的数据全都存到三个List<T>集合中,然后回到了该别本的迭代器。所以每一次访问迭代器,它都会新建叁个List<T>的别本,那样尽管浪费了迟早的储存空间,不过逻辑上进一步简便易行了。

/// <summary>
/// 本地帮助器方法释放所有本地列表锁
/// </summary>
private void ReleaseAllLocks()
{
    // 该方法用于在执行线程同步以后 释放掉所有本地锁
    // 通过遍历每个线程中存储的 ThreadLocalList对象 释放所占用的锁
    ThreadLocalList currentList = m_headList;
    while (currentList != null)
    {

        if (currentList.m_lockTaken)
        {
            currentList.m_lockTaken = false;
            Monitor.Exit(currentList);
        }
        currentList = currentList.m_nextList;
    }
}

/// <summary>
/// 从冻结状态解冻包的本地帮助器方法
/// </summary>
/// <param name="lockTaken">The lock taken result from the Freeze method</param>
private void UnfreezeBag(bool lockTaken)
{
    // 首先释放掉 每个线程中 本地变量的锁
    // 然后释放全局锁
    ReleaseAllLocks();
    m_needSync = false;
    if (lockTaken)
    {
        Monitor.Exit(GlobalListsLock);
    }
}

/// <summary>
/// 本地帮助器函数等待所有未同步的操作
/// </summary>
private void WaitAllOperations()
{
    Contract.Assert(Monitor.IsEntered(GlobalListsLock));

    ThreadLocalList currentList = m_headList;
    // 自旋等待 等待其它操作完成
    while (currentList != null)
    {
        if (currentList.m_currentOp != (int)ListOperation.None)
        {
            SpinWait spinner = new SpinWait();
            // 有其它线程进行操作时,会将cuurentOp 设置成 正在操作的枚举
            while (currentList.m_currentOp != (int)ListOperation.None)
            {
                spinner.SpinOnce();
            }
        }
        currentList = currentList.m_nextList;
    }
}

/// <summary>
/// 本地帮助器方法获取所有本地列表锁
/// </summary>
private void AcquireAllLocks()
{
    Contract.Assert(Monitor.IsEntered(GlobalListsLock));

    bool lockTaken = false;
    ThreadLocalList currentList = m_headList;

    // 遍历每个线程的ThreadLocalList 然后获取对应ThreadLocalList的锁
    while (currentList != null)
    {
        // 尝试/最后 bllock 以避免在获取锁和设置所采取的标志之间的线程港口
        try
        {
            Monitor.Enter(currentList, ref lockTaken);
        }
        finally
        {
            if (lockTaken)
            {
                currentList.m_lockTaken = true;
                lockTaken = false;
            }
        }
        currentList = currentList.m_nextList;
    }
}

/// <summary>
/// Local helper method to freeze all bag operations, it
/// 1- Acquire the global lock to prevent any other thread to freeze the bag, and also new new thread can be added
/// to the dictionary
/// 2- Then Acquire all local lists locks to prevent steal and synchronized operations
/// 3- Wait for all un-synchronized operations to be done
/// </summary>
/// <param name="lockTaken">Retrieve the lock taken result for the global lock, to be passed to Unfreeze method</param>
private void FreezeBag(ref bool lockTaken)
{
    Contract.Assert(!Monitor.IsEntered(GlobalListsLock));

    // 全局锁定可安全地防止多线程调用计数和损坏 m_needSync
    Monitor.Enter(GlobalListsLock, ref lockTaken);

    // 这将强制同步任何将来的添加/执行操作
    m_needSync = true;

    // 获取所有列表的锁
    AcquireAllLocks();

    // 等待所有操作完成
    WaitAllOperations();
}

/// <summary>
/// 本地帮助器函数返回列表中的包项, 这主要由 CopyTo 和 ToArray 使用。
/// 这不是线程安全, 应该被称为冻结/解冻袋块
/// 本方法是私有的 只有使用 Freeze/UnFreeze之后才是安全的 
/// </summary>
/// <returns>List the contains the bag items</returns>
private List<T> ToList()
{
    Contract.Assert(Monitor.IsEntered(GlobalListsLock));
    // 创建一个新的List
    List<T> list = new List<T>();
    ThreadLocalList currentList = m_headList;
    // 遍历每个线程中的ThreadLocalList 将里面的Node的数据 添加到list中
    while (currentList != null)
    {
        Node currentNode = currentList.m_head;
        while (currentNode != null)
        {
            list.Add(currentNode.m_value);
            currentNode = currentNode.m_next;
        }
        currentList = currentList.m_nextList;
    }

    return list;
}

/// <summary>
/// Returns an enumerator that iterates through the <see
/// cref="ConcurrentBag{T}"/>.
/// </summary>
/// <returns>An enumerator for the contents of the <see
/// cref="ConcurrentBag{T}"/>.</returns>
/// <remarks>
/// The enumeration represents a moment-in-time snapshot of the contents
/// of the bag.  It does not reflect any updates to the collection after 
/// <see cref="GetEnumerator"/> was called.  The enumerator is safe to use
/// concurrently with reads from and writes to the bag.
/// </remarks>
public IEnumerator<T> GetEnumerator()
{
    // Short path if the bag is empty
    if (m_headList == null)
        return new List<T>().GetEnumerator(); // empty list

    bool lockTaken = false;
    try
    {
        // 首先冻结整个 ConcurrentBag集合
        FreezeBag(ref lockTaken);
        // 然后ToList 再拿到 List的 IEnumerator
        return ToList().GetEnumerator();
    }
    finally
    {
        UnfreezeBag(lockTaken);
    }
}

由地点的代码可驾驭,为了拿到迭代器对象,总共进行了三步关键的操作。

  1. 使用FreezeBag()方法,冻结一切ConcurrentBag<T>聚集。因为急需改造集合的List<T>别本,生成副那时候期不能够有别的线程改进损坏数据。
  2. ConcurrrentBag<T>生成List<T>副本。因为ConcurrentBag<T>积攒数据的不二诀要比较新鲜,直接促成迭代器形式困难,寻思到线程安全和逻辑,最棒的方法是生成三个别本。
  3. 变成上述操作之后,就可以利用UnfreezeBag()方法解冻整个集结。

那么FreezeBag()措施是如何来冻结一切会集的啊?也是分为三步走。

  1. 第生龙活虎获得全局锁,通过Monitor.Enter(GlobalListsLock, ref lockTaken);如此这般一条语句,那样任何线程就不能够冻结群集。
  2. 下一场拿走具有线程中ThreadLocalList的锁,通过`AcquireAllLocks(卡塔尔国方法来遍历获取。那样任何线程就无法对它实行操作损坏数据。
  3. 等待已经跻身了操作流程线程结束,通过WaitAllOperations()艺术来落到实处,该方法会遍历每三个ThreadLocalList对象的m_currentOp性子,确认保证全部处在None操作。

姣好上述流程后,那么正是真正的结霜了全套ConcurrentBag<T>集聚,要解冻的话也近乎。在这里不再赘言。

ConcurrentHashMap

ConcurrentHashMap 的分子变量中,包涵了三个 Segment 的数组(final
Segment<K,V>[] segments;),而 Segment 是 ConcurrentHashMap
的个中类,然后在 Segment 这么些类中,满含了八个 HashEntry
的数组(transient volatile HashEntry<K,V>[] table;)。而
HashEntry 也是 ConcurrentHashMap 的里边类。HashEntry 中,包罗了 key 和
value 以致 next 指针(形似于 HashMap 中 Entry),所以 HashEntry
能够组成多个链表。

故此通俗的讲,ConcurrentHashMap 数据布局为三个 Segment 数组,Segment
的数据布局为 HashEntry 的数组,而 HashEntry
存的是我们的键值对,能够结合链表。

ConcurrentHashMap 的高并发性首要缘于于多个方面:

  • 用抽离锁完结多少个线程间的更加深档次的共享访谈。
  • 用 HashEntery
    对象的不变性来下滑施行读操作的线程在遍历链表时期对加锁的须要。
  • 经过对同多少个 Volatile 变量的写 / 读访谈,和煦分裂线程间读 /
    写操作的内部存款和储蓄器可以看到性。

行使分别锁,减小了央求 同多少个锁的作用。

经过 HashEntery 对象的不改变性及对同七个 Volatile 变量的读 /
写来和煦内部存款和储蓄器可以知道性,使得
读操作大多数时候无需加锁就能学有所成收获到须要的值。由于散列映射表在实际应用中山大学部分操作都以顺理成章的
读操作,所以 2 和 3
不仅可以够裁减须求同三个锁的效用,也得以使得压缩持有锁的年华。通过裁减央浼同一个锁的功效和尽量减弱持有锁的年月
,使得 ConcurrentHashMap 的并发性相对于 HashTable 和用一块包装器包装的
HashMap有了质的抓好。

四、总结

下边给出一张图,描述了ConcurrentBag<T>是何等存款和储蓄数据的。通过各样线程中的ThreadLocal来贯彻线程当地存款和储蓄,各样线程中都有那般的构造,互不忧虑。然后种种线程中的m_headList总是指向ConcurrentBag<T>的率先个列表,m_tailList本着最终叁个列表。列表与列表之间通过m_locals
下的 m_nextList连发,构成二个单链表。

数量存款和储蓄在各类线程的m_locals中,通过Node类构成四个双向链表。
PS:
要注意m_tailListm_headList并非储存在ThreadLocal中,而是有着的线程分享朝气蓬勃份。

伟德体育官网 58

上述就是至于ConcurrentBag<T>类的贯彻,小编的片段记下和剖析。

小编水平有限,固然不当招待各位商量指正!

附上ConcurrentBag<T>源码地址:戳一戳

发表评论