22 确保集合的线程安全
foreach不能代替for的一个原因是在迭代过程中对集合本身进行增删操作,同样在多线程中可能出现一个线程对集合进行迭代而另一个线程对集合进行增删操作:
class Program { static List<Person> personList = new List<Person> { new Person() { Name = "allen" } }; static AutoResetEvent autoSet = new AutoResetEvent(false); static void Main(string[] args) { Thread t1 = new Thread(() => { autoSet.WaitOne(); foreach (Person item in personList) { Console.WriteLine("t1:" + item.Name); Thread.Sleep(1000); } }); t1.Start(); Thread t2 = new Thread(() => { autoSet.Set(); Thread.Sleep(1000); personList.RemoveAt(0); Console.WriteLine("Delete"); }); t2.Start(); } class Person { public string Name { get; set; } } }
以上代码在运行过程中会抛出异常。
用ArrayList代替,保证其线程安全则应在迭代和修改是都加上lock,代码如下:
class Program { static ArrayList list = new ArrayList { new Person() { Name = "allen" } }; 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(() => { autoSet.Set(); Thread.Sleep(1000); lock(list.SyncRoot) { list.RemoveAt(0); Console.WriteLine("Delete"); } }); t2.Start(); } class Person { public string Name { get; set; } } }
用泛型时没有此属性,则可以new一个对象进行锁定:
class Program { static List<Person> personList = new List<Person> { new Person() { Name = "allen" } }; static AutoResetEvent autoSet = new AutoResetEvent(false); static object sycObj = new object(); static void Main(string[] args) { Thread t1 = new Thread(() => { autoSet.WaitOne(); lock(sycObj) { foreach (Person item in personList) { Console.WriteLine("t1:" + item.Name); Thread.Sleep(1000); } } }); t1.Start(); Thread t2 = new Thread(() => { autoSet.Set(); Thread.Sleep(1000); lock(sycObj) { personList.RemoveAt(0); Console.WriteLine("Delete"); } }); t2.Start(); } class Person { public string Name { get; set; } } }
Stay hungry, stay foolish

浙公网安备 33010602011771号