勇哥注:
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
版权声明:本文为博主原创文章,转载请附上博文链接!


少有人走的路


















