勇哥注:
ConcurrentBag是一个线程安全的无序集合。专为生产消费模式进行订制的集合。
如果多线程使用List<T>就会遇到问题:
System.InvalidOperationException:“集合已修改;可能无法执行枚举操作。”。
原因是timer2在遍历list的过程当中,timer1修改了list,使其大小发生了变化。
如果使用ConcurrentBag这类安全集合,可以避免这类问题出现。
它的常见方法如下:
Add 添加一个元素 TryPeek 方法返回一个元素,并且不删除原集合中的元素。 TryTake 返回元素并移除 FirstOrDefault 返回指定的元素 无论是TryPeek还是TryTake 都只是按先入先出取出数据。你想中间删除一个元素是做不到的。
用惯了List<T>,相比之下它的缺点如下:
不能下标访问,如data[0]
没有RmoveAt方法
即你没有办法删除到指定的元素
对于第2点,特别说明如下:
ConcurrentBag为每个线程保留一个线程本地队列,并且只有在其自己的队列变空时才查看其他线程的队列。如果您删除了一个项目并将其放回原来,那么您删除的下一个项目可能会再次成为同一个项目。无法保证重复删除项目并将其放回将允许您迭代所有项目。
两种替代方案:
删除所有项目并记住它们,直到找到要删除的项目,然后将其他项目放回原处。请注意,如果两个线程同时尝试执行此操作,则会出现问题。
使用更合适的数据结构,例如ConcurrentDictionary。
using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace WindowsFormsApplication1 { public partial class Form1 : Form { ConcurrentBag<string> buffer = new ConcurrentBag<string>(); public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { buffer.Add("windows32"); buffer.Add("linux"); buffer.Add("unix"); buffer.Add("os/2"); buffer.Add("windowsxp"); buffer.Add("win7"); buffer.Add("win10"); updateui(); } private void updateui() { listBox1.DataSource = null; var list2 = buffer.ToList(); list2.Reverse(); listBox1.DataSource = list2; } private void button2_Click(object sender, EventArgs e) { //取一个元素 string item1; buffer.TryPeek(out item1); richTextBox1.AppendText(item1); updateui(); //可以看到,取出的是尾巴上的元素 } private void button3_Click(object sender, EventArgs e) { //取一个元素并删除 string item1; buffer.TryTake(out item1); richTextBox1.AppendText(item1); updateui(); //可以看到,取出的是尾巴上的元素 } private void button4_Click(object sender, EventArgs e) { //取指定索引的元素 var selitem=buffer.FirstOrDefault(s => s == textBox1.Text); if(selitem==null) { MessageBox.Show($"找不到 {textBox1.Text}");return; } richTextBox1.AppendText(selitem); updateui(); } private void button5_Click(object sender, EventArgs e) { MessageBox.Show("请相信,你想既不损失效率的情况,又想轻易做到这一点,是不可能的。\n如果你正想这样做,那么你应该选择其它的数据结构,例如concurrentDictionary"); } private void Form1_Load(object sender, EventArgs e) { listBox1.Items.Clear(); } } }
测试代码下载:
---------------------
作者:hackpig
来源:www.skcircle.com
版权声明:本文为博主原创文章,转载请附上博文链接!

