b2科目四模拟试题多少题驾考考爆了怎么补救
b2科目四模拟试题多少题 驾考考爆了怎么补救

集合对象中线程安全_什么是线程安全的集合_线程安全的集合类(2)

电脑杂谈  发布时间:2017-04-08 22:22:38  来源:网络整理

示例代码2与示例代码1的区别仅在加锁操作上,变化的地方已经用红色字体标出。

再次运行代码,未报错,得到以下运行结果:

集合对象中线程安全_线程安全的集合类_什么是线程安全的集合

从结果我们可以看出,加锁以后,线程1执行的结果是正常的,正确的输出了list的10个元素。同样,线程2执行结果也是正常的,移除index=1,3的元素后,遍历出剩下的8个元素。不过这里要补充说明一下,移除index=1,3的元素时,为什么是源集合中的index=1,4的元素被移除?那是因为移除index=1的元素后,index=4的元素在新集合中的index就变成3了,所以会有这样的结果。

另外,在编写测试代码时,还遇到了下面这样一个问题,拿出来分享一下。

将线程2的代码改写成下面的形式。

Thread t2 = new Thread(() =>
{
     Thread.Sleep(1000);
     lock (sycObj)
     {
          foreach(var item in list)
          {
               if (item % 2 == 0)
               {
                    list.Remove(item);
               }
          }
          foreach (var item in list)
          {
               Console.WriteLine("t2.item:{0}", item);
          }
     }
});
t2.Start();

运行程序,你会发现,线程1能正常运行,但是在执行线程2时,同样会抛InvalidOperationException异常,提示信息仍为“集合已修改;可能无法执行枚举操作。”

分析代码,发现是在遍历集合并作移除操作的代码部分(已用青色字体标出),对于这点其实不在多线程程序中也是会出错的。很明显这种做法就不对,你既想遍历集合又想动态删除某些符合条件的元素,这是不可能的,哪有这么好的事。集合对象中线程安全

其实,除了加锁,还可以使用System.Collections.Concurrent命名空间中提供的ConcurrentBag<T>来代替List<T>,ConcurrentBag<T>是线程安全的集合类。

代码片段3:

线程安全的集合类_集合对象中线程安全_什么是线程安全的集合

using System;
using System.Collections.Generic;
using System.Threading;
using System.Collections.Concurrent;   //注1 

namespace CollSecExp
{
    class Program
    {        
        static void Main(string[] args)
        {
            ConcurrentBag<int> list = new ConcurrentBag<int>();
            for (int i = 0; i < 10; i)
            {
                list.Add(i); //注2
            }
 
            Thread t1 = new Thread(() =>
            {
                foreach (var item in list)
                {
                    Console.WriteLine("t1.item:{0}", item);
                    Thread.Sleep(1000);
                }
            });
            t1.Start();

            Thread t2 = new Thread(() =>
            {
                Thread.Sleep(1000);
                int a;
                list.TryTake(out a); //注3
                foreach (var item in list)
                {
                    Console.WriteLine("t2.item:{0}", item);
                }
            });
            t2.Start();
        }
    }
}

示例代码3与示例代码1的区别在于使用ConcurrentBag<int>来代替List<int>保存集合数据。这样一来就算不加锁,也能保证线程操作的同步。

有几点稍微补充说明一下:

[注1]需要引用命名空间System.Collections.Concurrent,才可以使用ConcurrentBag<T>类。

[注2]ConcurrentBag<T>的Add方法与List<T>的Add方法相同。集合对象中线程安全

[注3]ConcurrentBag<T>的移除方法为TryTake,与List<T>的移除方法不相同,这点需要注意。

运行程序,得到结果:

会发现线程1与线程2能正常运行,只是此时线程1,2会并行执行,且遍历集合时会从项大的到小的顺序进行,关于这点,以后再研究。

就到这里了。


本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/tongxinshuyu/article-40268-2.html

相关阅读
    发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

    • 李佳奇
      李佳奇

      早晚会还给历史公正的评价的

    • 郭梦乐
      郭梦乐

      教授本是代表了文化

    • 支凤琴
      支凤琴

      小编你是无知还是意淫

    热点图片
    拼命载入中...