并发访问列表:如果删除对象或列表设置为null会发生什么?

时间:2012-11-02 19:39:00

标签: c# multithreading concurrency locking

我有一个包含对象的列表列表<> my_objects 即可。几个线程可以更改此列表。我们假设我没有任何锁定机制来控制对列表的访问。

如果我正在使用列表的对象并且突然另一个线程将数组设置为null,会发生什么?

    MyObject o = my_objects[i];

    //now a second thread has set my_objects to null
    o.myMethod();

是否会发生NullPointerException?

此外,如果第二个线程在我在第一个线程中使用它时从列表中删除了所考虑的对象会发生什么?

   //second thread:
   //y = i
   MyObject o2 = my_objects[y];

   my_objects.Remove(o2);

5 个答案:

答案 0 :(得分:3)

  

如果我正在使用列表的对象并且突然另一个线程将数组设置为null,会发生什么?

如果你已经将有问题的引用复制到局部变量,那就没什么了。

如果另一个线程在此行之前将my_objects设置为null ,您将收到异常:

MyObject o = my_objects[i]; // my_objects must be non-null

o的值只是对象的引用。它有没有知道您从中获得它的列表或数组。收集可能是垃圾收集,任何事情都可能发生 - 参考和对象本身都不会受到影响。

(从列表中删除元素可能会导致问题,正如Henk所说 - List<T>不是线程安全的 - 但这与我理解你要问的问题不同。)

答案 1 :(得分:1)

在这两种情况下,您已经获得了对象的引用,更改列表对对象本身没有影响。由于对象本身的状态(例如NullReferenceException),您不会得到任何异常。

但是,由于对List<T>的并发访问,您可能会遇到其他异常。您应该在访问列表时使用锁定,或者更好的是,查看System.Collections.Concurrent命名空间中的类。

答案 2 :(得分:1)

MyObject o = my_objects[i];

//now a second thread has set my_objects to null, and/or invoked my_objects.Remove(o)
o.myMethod();

没关系。变量my_objects引用保存到对象,而不是对象本身。当您创建一个新变量o时,它会保存对同一对象的第二个引用。然后清除my_objects,这意味着您无法通过my_objects引用实际对象。但这并没有改变您仍然拥有o的事实,您仍然可以通过o引用实际对象。 (并且 反过来暗示对象本身仍然存在.C#是一种垃圾收集语言,对于第一个近似意味着保证对象保持不变直到你完成在这方面,非托管C ++是不同的,而Objective-C在第三种方式上有所不同。不是你问过的。)

实际上,在这方面, MyObject的引用就像int之类的原始类型一样。如果我有一个int的数组,我就是

int oi = my_ints[i];

然后我可以使用my_ints(清除它,从中移除项目)做任何我想做的事情,并且不会改变oi仍然存在的事实。

关于引用类型的内容,例如MyObject,以及您对此问题感到困惑的原因,是MyObject两个变量(omy_objects[i])仍然引用相同的实际对象,所以如果你通过my_objects[i].gainSpiderPowers()改变对象,无论你是否&你都会看到该突变的影响#39;通过my_objects[i]o重新查找。

答案 3 :(得分:0)

考虑使用ReadOnlyCollection。它位于System.Collections.ObjectModel命名空间中。

答案 4 :(得分:-1)

由于List<>被记录为不是线程安全的,并且您“不使用任何锁定”,因此结果是List中的竞争条件。

你可以获得各种异常,我见过 null reference index out of bounds

基本上语义是'未定义'。