C#程序编写高质量代码改善的157个建议【20-22】[泛型集合、选择集合、集合的安全]

 

建议20、使用泛型集合来替代非泛型集合html

http://www.cnblogs.com/aehyok/p/3384637.html 这里有一篇文章,是我以前专门来介绍泛型的。咱们应尽可能的使用泛型集合。由于泛型的确有它的好处:数组

一、提供了类型安全,在编译期间就能够检查错误安全

二、更重要的是大部分状况下泛型集合的性能比非泛型集合的性能都高不少。多线程

下面咱们来看一段简单的测试性能的代码:函数

复制代码
class Program { static int collectionCount = 0; static Stopwatch watch = null; static int testCount = 10000000; static void TestBegin() { GC.Collect(); ////强制对全部代码进行即时垃圾回收 GC.WaitForPendingFinalizers();////挂起线程,执行终结器队列中的终结器(即析构方法) GC.Collect();///再次对全部代码进行垃圾回收,主要包括从终结器队列中出来的对象 collectionCount = GC.CollectionCount(0);///返回在0代中执行的垃圾回收次数 watch = new Stopwatch(); watch.Start(); } static void TestEnd() { watch.Stop(); Console.WriteLine("耗时:{0}",watch.ElapsedMilliseconds.ToString()); Console.WriteLine("垃圾回收次数:{0}", GC.CollectionCount(0) - collectionCount); } static void TestArrayList() { ArrayList arrayList = new ArrayList(); int temp = 0; for (int i = 0; i < testCount; i++) { arrayList.Add(i); temp = (int)arrayList[i]; } arrayList = null; } static void TestGenericList() { List<int> list = new List<int>(); int temp = 0; for (int i = 0; i < testCount; i++) { list.Add(i); temp = list[i]; } list = null; } static void Main(string[] args) { Console.WriteLine("开始测试ArrayList"); TestBegin(); TestArrayList(); TestEnd(); Console.WriteLine("开始测试List<T>"); TestBegin(); TestGenericList(); TestEnd(); Console.ReadLine(); } }
复制代码

执行结果以下性能

   我上面测试的次数是10000000,能够发现,二者在垃圾回收次数和耗时都差距比较大,因此泛型集合有着非泛型集合没法超越的优点。因此仍是尽可能在咱们的程序中使用泛型集合吧。测试

建议2一、选择正确的集合spa

 http://www.cnblogs.com/aehyok/p/3643928.html这里有一篇我刚写的关于集合的博文,主要是简单介绍了一下关于本身使用比较频繁的几个集合。pwa

若是集合的数目固定而且不涉及转型,使用数组效率高,不然就是使用List<T>。线程

像使用数组、ArrayList、List<T>、Dictionary<key,value>这些集合的有点就是插入和删除数据效率比较高,缺点就是查找的效率相对来讲低一些。

关于队列能够参考http://msdn.microsoft.com/zh-cn/library/System.Collections.Queue(v=vs.80).aspx

关于栈能够参考http://msdn.microsoft.com/zh-cn/library/System.Collections.Stack(v=vs.110).aspx

建议2二、确保集合的线性安全

   建议18中提到,foreach循环不能代替for循环的一个缘由是在迭代过程当中对集合自己进行了增删操做。将此场景移植到多线程场景中,就是本建议要阐述的重点:确保集合的线程安全。集合线程安全是指在多个线程上添加活删除元素时,线程之间必须保持同步。

  下面咱们来经过实例来更详细的查看一下,先简单定义一个实体类

public class Person { public string Name { get; set; } public int Age { get; set; } }
复制代码
static List<Person> list = new List<Person>() { new Person(){ Name="aehyok",Age=25}, new Person(){Name="Kris",Age=23}, new Person(){Name="Leo",Age=26} }; static AutoResetEvent autoSet = new AutoResetEvent(false); static void Main(string[] args) { Thread t1 = new Thread(() => { ///阻止当前线程  autoSet.WaitOne(); foreach (var item in list) { Console.WriteLine("t1:"+item.Name); Thread.Sleep(1000); } }); t1.Start(); Thread t2 = new Thread(() => { ///通知t1能够执行代码  autoSet.Set(); Thread.Sleep(1000); list.RemoveAt(2); }); t2.Start(); Console.ReadLine(); }
复制代码

再来简单分析一下这段代码,其实就是闲定义了一个List集合,而后又定义了一个 AutoRestEvent的实例,用于控制线程的。

接下来在Main函数中定义了两个线程,在线程一中将线程一暂停,而后当调用线程二的时候再来通知线程一继续运行。最终运行结果

 

主要是由于线程一在暂停以后,开始运行线程二随即线程一获得通知能够继续运行,经过代码能够发现都有Thread.Sleep(1000);也就是为了保证两个线程都还在运行期间,线程二移除了集合中的一个元素,那么当线程一再次循环的时候,致使了错误的发生。

早在泛型集合出现以前,非泛型集合通常会提供一个SyncRoot属性,要保证非泛型集合的线程安全,能够经过锁定该属性来实现。若是上面的集合用ArrayList代替,保证线程安全则应该在迭代和删除的时候都加上锁lock,代码以下所示:

复制代码
static ArrayList list = new ArrayList() { new Person(){ Name="aehyok",Age=25}, new Person(){Name="Kris",Age=23}, new Person(){Name="Leo",Age=26} }; static AutoResetEvent autoSet = new AutoResetEvent(false); static void Main(string[] args) { Thread t1 = new Thread(() => { ///阻止当前线程  autoSet.WaitOne(); lock (list.SyncRoot) { foreach (Person item in list) { Console.WriteLine("t1:" + item.Name); Thread.Sleep(1000); } } }); t1.Start(); Thread t2 = new Thread(() => { ///通知t1能够执行代码  autoSet.Set(); Thread.Sleep(1000); lock (list.SyncRoot) { list.RemoveAt(2); } }); t2.Start(); Console.ReadLine(); }
复制代码

运行结果就是线程一执行经过

若是你试过,那么会发现泛型集合没有这样的属性来进行加锁,必需要本身建立一个锁定对象来完成同步的任务。

因此第一个例子咱们能够这样进行修改

复制代码
static List<Person> list = new List<Person>() { new Person(){ Name="aehyok",Age=25}, new Person(){Name="Kris",Age=23}, new Person(){Name="Leo",Age=26} }; static object SyncObject = new object(); static AutoResetEvent autoSet = new AutoResetEvent(false); static void Main(string[] args) { Thread t1 = new Thread(() => { ///阻止当前线程  autoSet.WaitOne(); lock (SyncObject) { foreach (var item in list) { Console.WriteLine("t1:" + item.Name); Thread.Sleep(1000); } } }); t1.Start(); Thread t2 = new Thread(() => { ///通知t1能够执行代码  autoSet.Set(); Thread.Sleep(1000); lock (SyncObject) { list.RemoveAt(2); } }); t2.Start(); Console.ReadLine(); }
相关文章
相关标签/搜索