为什么我们在这里特别提到 ArrayList 不是线程安全的呢?

huangapple go评论67阅读模式
英文:

Why are we here, specifically, saying that ArrayList is not thread safe?

问题

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

英文:

Description: If we use same object reference among multiple threads, no object is thread safe. Similarly, if any collection reference is shared among multiple threads then that collection is not thread-safe since other threads can access it. So, Why are we here specifically saying that ArrayList is not thread-safe? What about the other Collections?

答案1

得分: 2

你误解了“线程安全”的意思。

当我们说“类X是线程安全的”时,我们并 不是 不需要担心使用它的程序的线程安全性。如果你构建一个仅使用线程安全对象的程序,并 不保证 你的程序将是线程安全的。

那么它 确保 什么呢?

假设你有一个 List。假设两个线程A和B分别写入不同的值到列表中的相同索引,假设某个线程C从该索引读取,假设这三个线程都没有使用任何同步。

如果这个列表是“线程安全”的,那么你可以确保线程C将获得三种可能的值之一:

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

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

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

当我们说一个类是“线程安全”的时候,我们是在说即使它的方法被多个线程同时调用,它也会始终表现出可预测、合理的方式。

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

英文:

You misunderstand the meaning of "thread-safe."

When we say "class X is thread-safe," We are not saying that you don't have to worry about the thread-safety of a program that uses it. If you build a program using nothing but thread-safe objects, that does not guarantee that your program will be thread-safe.

So what does it guarantee?

Suppose you have a List. Suppose that two threads, A and B, each write different values to the same index in the list, suppose that some thread C reads from that index, and suppose that none of those three threads uses any synchronization.

If the list is "thread-safe," then you can be assured that thread C will get one of three possible values:

  • The value that thread A wrote,
  • The value that thread B wrote,
  • The value that was stored at that index before either thread A or thread B wrote.

If the list is not thread-safe, then any of those same three things could happen, but also, other things could happen:

  • Thread C could get a value that was never in the list,
  • The list could behave in broken ways in the future for thread C even if no other thread continues to use it,
  • The program could crash,
  • etc. (I don't know how many other strange things could happen.)

When we say that a class is "thread-safe" we are saying that it will always behave in predictable, reasonable ways, even when its methods are concurrently called by multiple threads.

If you write a program that uses a "thread-safe" list, and if it depends on thread C reading one particular value of the three possibilities that I listed above, then your program has a thread-safety problem, even though the list itself does not.

答案2

得分: 1

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

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

英文:

I haven't checked but I think that all standard Collection implementations state if they are thread-safe or not. So you know if you can share that collection among different threads without synchronization.

CopyOnWriteArrayList for example is a thread-safe List implementation.

答案3

得分: 0

ArrayList 在实现中是不同步的。当一个对象是不同步的,意味着在结构性修改时不会被锁定。"结构性修改是指添加或删除一个或多个元素的任何操作,或显式调整支持数组的大小;仅设置元素的值不是结构性修改。"

你所指的是一个数组,其中元素正在被添加或删除,可以被修改,这与仅设置其值不同。

引用是关于数组起始指针的,但有多少元素存在是个问题,而且在另一个线程遍历元素时修改一个不同步的对象,很难保证列表中元素的完整性。希望我能清楚地传达这个信息。

在 Oracle 中查找更多详细信息:Array ListConcurrentModificationException

ArrayList:

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

ConcurrentModificationException:

注意,无法保证快速失败行为,因为在不同步的并发修改存在的情况下,通常情况下不可能在硬性保证。

英文:

ArrayList is unsynchronized in implementation. When an object is unsynchronized it means that is is not locked while being modified structurally. 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.
What you are referring to is an array which the elements are being added to or being deleted from and can be modified this differs from it having its value being set.

Reference is in regards with the pointer of the start of the array but how many elements are there is in question and having an unsynchronized object being modified in the sense of elements while the elements are being iterated over by another thread the integrity of the elements in the list is hard to guarantee. I hope I was able to convey the message plainly.

Look for more details here in Oracle: Array List and ConcurrentModificationException

ArrayList:
> Note that this implementation is not synchronized. If multiple threads access an ArrayList instance concurrently, and at least one of the threads modifies the list structurally, it must be synchronized externally. (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.) This is typically accomplished by synchronizing on some object that naturally encapsulates the list. If no such object exists, the list should be "wrapped" using the Collections.synchronizedList method.

ConcurrentModificationException:
> Note that fail-fast behavior cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification.

huangapple
  • 本文由 发表于 2020年4月7日 18:48:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/61078300.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定