为什么我们在这里,特别是说ArrayList不是线程安全的



描述:如果我们在多个线程之间使用相同的对象引用,则没有对象是线程安全的。类似地,如果任何集合引用在多个线程之间共享,那么该集合就不是线程安全的,因为其他线程可以访问它。那么,为什么我们在这里特别说ArrayList不是线程安全?其他收藏品呢?

您误解了"线程安全"的含义

当我们说"类X是线程安全的"时,我们不是说不必担心使用它的程序的线程安全。如果你只使用线程安全对象来构建程序,就不能保证你的程序是线程安全。

那么能保证什么呢?

假设您有一个List。假设两个线程A和B各自向列表中的同一索引写入不同的值,假设某个线程C从该索引中读取,并且假设这三个线程都不使用任何同步。

如果列表是"线程安全的",那么可以确信线程C将获得三个可能值之一:

  • 线程A写入的值
  • 线程B写入的值
  • 在线程A或线程B写入之前存储在该索引处的值

如果列表不是线程安全的,那么这三件事中的任何一件都可能发生,但也可能发生其他事情:

  • 线程C可以获得从未在列表中的值
  • 对于线程C,即使没有其他线程继续使用该列表
  • 程序可能会崩溃
  • 等等。(我不知道还会发生多少其他奇怪的事情。(

当我们说一个类是"线程安全的"时,我们是说它总是以可预测的、合理的方式运行,即使它的方法由多个线程同时调用。

如果您编写的程序使用"线程安全"列表,并且它依赖于线程C读取我上面列出的三种可能性中的一个特定值,那么您的程序存在线程安全问题,即使列表本身没有。

我没有检查过,但我认为所有标准Collection实现都会说明它们是否是线程安全的。因此,您知道是否可以在不同步的情况下在不同线程之间共享该集合。

例如,CopyOnWriteArrayList是一个线程安全的List实现。

ArrayList在实现中是不同步的。当一个对象不同步时,意味着在结构上进行修改时该对象未被锁定。A structural modification is any operation that adds or deletes one or more elements, or explicitly resizes the backing array; merely setting the value of an element is not a structural modification.您所指的是一个数组,元素将被添加到该数组或从中删除,并且可以进行修改,这与设置其值不同。

引用是关于数组开头的指针,但有多少元素是有问题的,并且当元素被另一个线程迭代时,在元素的意义上修改一个未同步的对象,很难保证列表中元素的完整性。我希望我能够清楚地传达这个信息。

在Oracle:Array List和ConcurrentModificationException 中查找更多详细信息

阵列列表:

请注意,此实现不是同步的。如果多个线程同时访问一个ArrayList实例,并且至少有一个线程在结构上修改了该列表,则必须对其进行外部同步。(结构修改是指添加或删除一个或多个元素,或显式调整支持数组大小的任何操作;仅仅设置元素的值并不是结构修改。(这通常是通过对自然封装列表的某个对象进行同步来实现的。如果不存在这样的对象,则应使用Collections.synchronizedList方法"包装"列表。

ConcurrentModificationException:

请注意,不能保证故障快速行为,因为一般来说,在存在不同步的并发修改的情况下,不可能做出任何硬保证。

相关内容

最新更新