一. 各类数据结构比较及其线程安全问题

1. Array(数组):

  分配在连续内存中,不能随意扩展,数组中数值类型必须是一致的。数组的声明有两种形式:直接定义长度,然后赋值;直接赋值。

  缺点:插入数据慢。

  优点:性能高,数据再多性能也没有影响

  特别注意:Array不是线程安全,在多线程中需要配合锁机制来进行,如果不想使用锁,可以用ConcurrentStack这个线程安全的数组来替代Array。

  1. {
  2. Console.WriteLine("---------------------------01 Array(数组)-----------------------------------");
  3. //模式一:声明数组并指定长度
  4. int[] array = new int[];
  5. //数组的赋值通过下标来赋值
  6. for (int i = ; i < array.Length; i++)
  7. {
  8. array[i] = i + ;
  9. }
  10. //数组的修改通过下标来修改
  11. array[] = ;
  12. //输出
  13. for (int j = ; j < array.Length; j++)
  14. {
  15. Console.WriteLine(array[j]);
  16. }
  17.  
  18. //模式二:直接赋值
  19. string[] array2 = new string[] { "二胖", "二狗" };
  20. }

2. ArrayList(可变长度的数组)

  不必在声明的时候指定长度,即长度可变;可以存放不同的类型的元素。

  致命缺点:无论什么类型存到ArrayList中都变为object类型,使用的时候又被还原成原先的类型,所以它是类型不安全的,当值类型存入的时候,会发生装箱操作,变为object引用类型,而使用的时候,又将object类型拆箱,变为原先的值类型,这尼玛,你能忍?

  结论:不推荐使用,建议使用List代替!!

  特别注意:ArrayList不是线程安全,在多线程中需要配合锁机制来进行。

  1. {
  2. Console.WriteLine("---------------------------02 ArrayList(可变长度的数组)-----------------------------------");
  3. ArrayList arrayList = new ArrayList();
  4. arrayList.Add("二胖");
  5. arrayList.Add("马茹");
  6. arrayList.Add();
  7. for (int i = ; i < arrayList.Count; i++)
  8. {
  9. Console.WriteLine(arrayList[i] + "类型为:" + arrayList[i].GetType());
  10. }
  11. }

3. List<T> (泛型集合) 推荐使用

  内部采用array实现,但没有拆箱和装箱的风险,是类型安全的

  特别注意:List<T>不是线程安全,在多线程中需要配合锁机制来进行,如果不想使用锁,可以用ConcurrentBag这个线程安全的数组来替代List<T>

  1. {
  2. Console.WriteLine("---------------------------03 List<T> (泛型集合)-----------------------------------");
  3. List<string> arrayList = new List<string>();
  4. arrayList.Add("二胖");
  5. arrayList.Add("马茹");
  6. arrayList.Add("大胖");
  7. //修改操作
  8. arrayList[] = "葛帅";
  9. //删除操作
  10. //arrayList.RemoveAt(0);
  11. for (int i = ; i < arrayList.Count; i++)
  12. {
  13. Console.WriteLine(arrayList[i]);
  14. }
  15. }

4. LinkedList<T> 链表

  在内存空间中存储的不一定是连续的,所以和数组最大的区别就是,无法用下标访问。

  优点:增加删除快,适用于经常增减节点的情况。

  缺点:无法用下标访问,查询慢,需要从头挨个找。

  特别注意:LinkedList<T>不是线程安全,在多线程中需要配合锁机制来进行。

  1. {
  2. Console.WriteLine("---------------------------04 ListLink<T> 链表-----------------------------------");
  3. LinkedList<string> linkedList = new LinkedList<string>();
  4. linkedList.AddFirst("二胖");
  5. linkedList.AddLast("马茹");
  6.  
  7. var node1 = linkedList.Find("二胖");
  8. linkedList.AddAfter(node1, "三胖");
  9. //删除操作
  10. linkedList.Remove(node1);
  11. //查询操作
  12. foreach (var item in linkedList)
  13. {
  14. Console.WriteLine(item);
  15. }
  16. }

5. Queue<T> 队列

  先进先出,入队(Enqueue)和出队(Dequeue)两个操作

  特别注意:Queue<T>不是线程安全,在多线程中需要配合锁机制来进行,如果不想使用锁,线程安全的队列为 ConcurrentQueue。

  实际应用场景:利用队列解决高并发问题(详见:http://www.cnblogs.com/yaopengfei/p/8322016.html)

  1. {
  2. Console.WriteLine("---------------------------05 Queue<T> 队列-----------------------------------");
  3. Queue<int> quereList = new Queue<int>();
  4. //入队操作
  5. for (int i = ; i < ; i++)
  6. {
  7. quereList.Enqueue(i + );
  8. }
  9. //出队操作
  10. while (quereList.Count != )
  11. {
  12. Console.WriteLine(quereList.Dequeue());
  13. }
  14. }

6. Stack<T> 栈

  后进先出,入栈(push)和出栈(pop)两个操作

  特别注意:Stack<T>不是线程安全

  1. {
  2. Console.WriteLine("---------------------------06 Stack<T> 栈-----------------------------------");
  3. Stack<int> stackList = new Stack<int>();
  4. //入栈操作
  5. for (int i = ; i < ; i++)
  6. {
  7. stackList.Push(i + );
  8. }
  9. //出栈操作
  10. while (stackList.Count != )
  11. {
  12. Console.WriteLine(stackList.Pop());
  13. }
  14. }

7. Hashtable

  典型的空间换时间,存储数据不能太多,但增删改查速度非常快。

  特别注意:Hashtable是线程安全的,不需要配合锁使用。

  1. {
  2. Console.WriteLine("---------------------------07 Hashtable-----------------------------------");
  3. Hashtable tableList = new Hashtable();
  4. //存储
  5. tableList.Add("", "马茹");
  6. tableList[""] = "二胖";
  7. //查询
  8. foreach (DictionaryEntry item in tableList)
  9. {
  10. Console.WriteLine("key:{0},value:{1}", item.Key.ToString(), item.Value.ToString());
  11. }
  12. }

8. Dictionary<K,T>字典 (泛型的Hashtable)

  增删改查速度非常快,可以用来代替实体只有id和另一个属性的时候,大幅度提升效率。

  特别注意:Dictionary<K,T>不是线程安全,在多线程中需要配合锁机制来进行,如果不想使用锁,线程安全的字典为 ConcurrentDictionary。

  1. {
  2. Console.WriteLine("---------------------------08 Dictionary<K,T>字典-----------------------------------");
  3. Dictionary<string, string> tableList = new Dictionary<string, string>();
  4. //存储
  5. tableList.Add("", "马茹");
  6. tableList.Add("", "二胖");
  7. tableList[""] = "三胖";
  8. //查询
  9. foreach (var item in tableList)
  10. {
  11. Console.WriteLine("key:{0},value:{1}", item.Key.ToString(), item.Value.ToString());
  12. }
  13. }

强调: 

以上8种类型,除了Hashtable是线程安全,其余都不是,都需要配合lock锁来进行,或者采用 ConcurrentXXX来替代。

详细的请见:http://www.cnblogs.com/yaopengfei/p/8322016.html

二. 四大接口比较

1. IEnumerable

  是最基本的一个接口,用于迭代使用,里面有GetEnumerator方法。

2. ICollection

  继承了IEnumerable接口,主要用于集合,内部有Count属性表示个数,像ArrayList、List、LinkedList均实现了该接口。

3. IList

  继承了IEnumerable 和 ICollection,实现IList接口的数据接口可以使用索引访问,表示在内存上是连续分配的,比如Array、List。

4. IQueryable

  这里主要和IEnumerable接口进行对比。

  Enumerable里实现方法的参数是Func委托,Queryable里实现的方法的参数是Expression表达式。

  实现IQueryable和IEnumabler均为延迟加载,但二者的实现方式不同,前者为迭代器模式,参数为Func委托,后者为Expression表达式目录树实现。

三. yield关键字

1. yield必须出现在IEunmerable中

2. yield是迭代器的状态机,能做到延迟查询,使用的时候才查询,可以实现按序加载

3. 例子

  测试一:在 “var data1 = y.yieldWay();”加一个断点,发现直接跳过,不能进入yieldWay方法中,而在“foreach (var item in data1)”加一个断点,第一次遍历的时候就进入了yieldWay方法中,说明了yield是延迟加载的,只有使用的时候才查询。

  测试二:对yieldWay和commonWay获取的数据进行遍历,通过控制台发现前者是一个一个输出,而后者是先一次性获取完,一下全部输出来,证明了yield可以做到按需加载,可以在foreach中加一个限制,比如该数据不满足>100就不输出。

  1. //********************************* 下面为对比普通返回值和使用yeild返回值的方法 ************************************************
  2.  
  3. /// <summary>
  4. /// 含yield返回值的方法
  5. /// </summary>
  6. /// <returns></returns>
  7. public IEnumerable<int> yieldWay()
  8. {
  9. for (int i = ; i < ; i++)
  10. {
  11. yield return this.Get(i);
  12. }
  13. }
  14. /// <summary>
  15. /// 普通方法
  16. /// </summary>
  17. /// <returns></returns>
  18. public IEnumerable<int> commonWay()
  19. {
  20. int[] intArray = new int[];
  21. for (int i = ; i < ; i++)
  22. {
  23. intArray[i] = this.Get(i);
  24. }
  25. return intArray;
  26. }
  27.  
  28. /// <summary>
  29. /// 一个获取数据的方法
  30. /// </summary>
  31. /// <param name="num"></param>
  32. /// <returns></returns>
  33. private int Get(int num)
  34. {
  35. Thread.Sleep();
  36. return num * DateTime.Now.Second;
  37. }
  1. Console.WriteLine("-----------------------下面是调用yield方法-----------------------");
  2. yieldDemo y = new yieldDemo();
  3. var data1 = y.yieldWay();
  4. foreach (var item in data1)
  5. {
  6. Console.WriteLine(item);
  7. }
  8. Console.WriteLine("-----------------------下面是调用普通方法-----------------------");
  9. var data2 = y.commonWay();
  10. foreach (var item in data2)
  11. {
  12. Console.WriteLine(item);
  13. }

!

  • 作       者 : Yaopengfei(姚鹏飞)
  • 博客地址 : http://www.cnblogs.com/yaopengfei/
  • 声     明1 : 本人才疏学浅,用郭德纲的话说“我是一个小学生”,如有错误,欢迎讨论,请勿谩骂^_^。
  • 声     明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
 

第三节:深度剖析各类数据结构(Array、List、Queue、Stack)及线程安全问题和yeild关键字的更多相关文章

  1. ASP.NET MVC深入浅出系列(持续更新) ORM系列之Entity FrameWork详解(持续更新) 第十六节:语法总结(3)(C#6.0和C#7.0新语法) 第三节:深度剖析各类数据结构(Array、List、Queue、Stack)及线程安全问题和yeild关键字 各种通讯连接方式 设计模式篇 第十二节: 总结Quartz.Net几种部署模式(IIS、Exe、服务部署【借

    ASP.NET MVC深入浅出系列(持续更新)   一. ASP.NET体系 从事.Net开发以来,最先接触的Web开发框架是Asp.Net WebForm,该框架高度封装,为了隐藏Http的无状态模 ...

  2. 【C#复习总结】探究各类数据结构(Array、List、Queue、Stack)及线程安全问题和yeild关键字

    前言 先普及一下线程安全和类型安全 线程安全: 如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码.如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的 ...

  3. .NET面试题系列(五)数据结构(Array、List、Queue、Stack)及线程安全问题

    常用数据结构的时间复杂度 如何选择数据结构 Array (T[]) 当元素的数量是固定的,并且需要使用下标时. Linked list (LinkedList<T>) 当元素需要能够在列表 ...

  4. libevent学习笔记(参考libevent深度剖析)

    最近自学libevent事件驱动库,参考的资料为libevent2.2版本以及张亮提供的<Libevent源码深度剖析>, 参考资料: http://blog.csdn.net/spark ...

  5. 大众点评开源分布式监控平台 CAT 深度剖析

    一.CAT介绍 CAT系统原型和理念来源于eBay的CAL的系统,CAT系统第一代设计者吴其敏在eBay工作长达十几年,对CAL系统有深刻的理解.CAT不仅增强了CAL系统核心模型,还添加了更丰富的报 ...

  6. js对象详解(JavaScript对象深度剖析,深度理解js对象)

    js对象详解(JavaScript对象深度剖析,深度理解js对象) 这算是酝酿很久的一篇文章了. JavaScript作为一个基于对象(没有类的概念)的语言,从入门到精通到放弃一直会被对象这个问题围绕 ...

  7. 深度剖析HashMap的数据存储实现原理(看完必懂篇)

    深度剖析HashMap的数据存储实现原理(看完必懂篇) 具体的原理分析可以参考一下两篇文章,有透彻的分析! 参考资料: 1. https://www.jianshu.com/p/17177c12f84 ...

  8. planning深度剖析

    planning深度剖析 结合find命令过滤目录及文件名后缀: find /home/hadoop/nisj/automationDemand/ -type f -name '*.py'|xargs ...

  9. 3.3.4深度剖析ConcurrentLinkedQueue

    队列.链表之类的数据结构及其常用.Java中,ArrayList和Vector都是使用数组作为其内部实现.两者最大的不同在于:Vector是线程安全的,而ArrayList不是.此外LinkedLis ...

随机推荐

  1. 2016 西普杯丶天津CTF预选赛(3/6)

    哆啦A梦(图片隐写) 格式:SimCTF{ } 解:放到kail中binwalk一下(Binwalk是一个固件的分析工具,旨在协助研究人员对固件非分析,提取及逆向工程用处.简单易用,完全自动化脚本,并 ...

  2. Redis操作string

    Redis简介: ''' redis: 缓存,例如两个个程序A,B之间要进行数据共享,A可以把数据存在redis(内存里),其他程序都可以访问redis里的数据, 这样通过中间商redis就实现了两个 ...

  3. 【Python 21】52周存钱挑战1.0

    1.案例描述 按照52周存钱法,存钱人必须在一年52周内,每周递存10元.例如,第一周存10元,第二周存20元,第三周存30元,直到第52周存520元. 记录52周后能存多少钱?即10+20+30+. ...

  4. HBase源码实战:CreateRandomStoreFile

    /* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agre ...

  5. Spark-RDD之Partition源码分析

    概要 Spark RDD主要由Dependency.Partition.Partitioner组成,Partition是其中之一.一份待处理的原始数据会被按照相应的逻辑(例如jdbc和hdfs的spl ...

  6. day2 and day3 总结-python基础-坚持就是胜利

    今日份快捷键学习,pycharm中按CTRL+ALT+L 自动规范化操作,不过和QQ的快捷键会有冲突,建议更改QQ的 知识点: 1.编码 2.while循环 3.运算符 4.数字int 5.布尔值 6 ...

  7. day4-python基础-小数据池以及深浅copy浅讲

    今天的目录是 1.小数据池 2.深浅copy 正文开始 1.小数据池 在说明今天的内容前,先说明一个在今天重复用到的一个知识点 ###比较’=’俩边的数据是否完全相同,以及判断一个对象的内存地址是否完 ...

  8. 移动端无限滚动 TScroll.vue组件

    // 先看使用TScroll.vue的几个demo 1.https://sorrowx.github.io/TScroll/#/ 2. https://sorrowx.github.io/TScrol ...

  9. spring cloud中feign的使用

    我们在进行微服务项目的开发的时候,经常会遇到一个问题,比如A服务是一个针对用户的服务,里面有用户的增删改查的接口和方法,而现在我有一个针对产品的服务B服务中有一个查找用户的需求,这个时候我们可以在B服 ...

  10. CodeForces Round #553 Div2

    A. Maxim and Biology 代码: #include <bits/stdc++.h> using namespace std; int N; string s; int mi ...