线程安全是否意味着没有竞争条件?

Does thread-safe mean no race conditions?

ConcurrentHashMap 是线程安全的,但可能会出现竞争条件,因为据我所知,只有部分地图被锁定并且仅用于写入操作,这意味着如果同时有读取操作,将会发生竞争条件。

不过我也喜欢看这里https://en.wikipedia.org/wiki/Thread_safety

Thread safe: Implementation is guaranteed to be free of race conditions when accessed by multiple threads simultaneously.

我能说ConcurrentHashMap是线程安全的,但不是完全同步的吗?这里的正确术语是什么?

当一个实体被多个访问者同时更新或修改时,就会发生竞争情况。对于单纯的读取,不存在竞争条件,因为读取与更新或修改不同。


ConcurrentHashMap 是线程安全的意味着这个 DS 中可能出现竞争条件的方面已经得到处理。

因此...是的,尽管并非 ConcurrentHashMap 中的所有方法都受到并发访问的保护,但 ConcurrentHashMap 是线程安全的,因为对于这些方法并发访问不是问题。

不知道"thread safe."有正式定义

当人们说某些 class 是线程安全的时,他们通常意味着多个线程并发使用 class 方法不会导致行为这会让阅读过 class 文档的通情达理的程序员感到惊讶。

"Thread safe" 对于 Map 意味着:

  • 如果两个或多个线程存储不同的键,所有的存储都会发生。
  • 如果两个或多个线程为同一个键存储不同的值,至少会发生其中一种存储。
  • 如果一个线程存储键的值而另一个线程试图获取该键的值,则读取线程将获取旧值或新值。
  • 键 K 的值永远不会改变,因为多个线程访问 and/or 存储其他键。
  • 多个线程并发使用同一个映射永远不会导致 JVM 抛出 VirtualMachineError 或导致段错误。
  • 等等

请注意,上面的某些示例是 class 本身无力阻止的竞争条件示例。 "Thread safe" 不是 如果您使用线程安全 class,您的程序将不会出现竞争条件的承诺。它只承诺 class 自己的源代码不会成为您程序中与线程相关的错误的原因。

but race conditions can occur, because (snip)

因为任何 "thread safe" 原语的任何非平凡使用,甚至是互斥锁,都涉及竞争,根据定义

如果没有竞争访问资源,你甚至不会关心"thread safety",因为访问是顺序的.

我会说是的线程安全意味着没有数据竞争的可能性。

因为线程安全意味着:“如果数据类型或静态方法在多个线程中使用时 行为正确,则该数据类型或静态方法是线程安全的,无论这些线程如何执行,并且不需要调用代码进行额外的协调。” (MIT, course on Software Construction)

竞争条件基本上是线程安全代码中不会发生的情况:“竞争条件是一种缺陷,当事件的时间或顺序影响程序的正确性时”。 (John Regehr, University of Utah)

TL;DR

"Thread-safe" 可能取决于主观解释,而“竞争条件”更 objective 和抽象。

解释:

例如,在 C++ 中,`cout` "as such" 在它自己的实现级别是 thread-safe。当从多个线程并行调用 `cout` 时,您不会看到您的应用程序崩溃或向单个控制台(共享资源)输出乱码。

但是,如果您使用 cout 从并行线程输出您的文本字符串,有时您会看到您的文本在字符序列级别混乱,因为毫无疑问存在竞争条件。

是否意味着 cout 不是 thread-safe?我倾向于“不”,因为 C++ 标准说它 thread-safe 就足够了(稍后我会 return)。

这是否意味着您的代码不是 thread-safe?视情况而定。

如果输出混合文本片段是您和您代码的用户所期望的,那么从用户的角度来看,该代码可以被视为 thread-safe,尽管它存在竞争条件(访问共享资源 -控制台 - 不同步)。

但是如果有人抱怨你必须重写你的代码,那么这意味着它被认为 thread-safe 不够。

因此,“不是 thread-safe”可能被宽泛地定义为“由于竞争条件导致不希望的行为”。

如果不存在由于竞争条件导致的不良行为,则可能取决于主观解释。我想说的是,从用户的角度来看,代码可能仍被视为 thread-safe,尽管从技术上讲,这并不是因为它忽略了竞争条件。

返回控制台输出主题。在 .NET 中,Microsoft 似乎认为 C++ 的控制台输出 thread-safe 不够(再次如此 - 主观解释),因此他们以不同的方式实现它,您可以将整个字符串输出到 Console.Write 而无需混合来自不同的线程。

引用 Microsoft 关于其 .NET 控制台的内容:

I/O operations that use these streams are synchronized, which means that multiple threads can read from, or write to, the streams.

并引用 C++ 标准:

Concurrent access to a synchronized (§27.5.3.4) standard iostream object’s formatted and unformatted input (§27.7.2.1) and output (§27.7.3.1) functions or a standard C stream by multiple threads shall not result in a data race (§1.10). [ Note: Users must still synchronize concurrent use of these objects and streams by multiple threads if they wish to avoid interleaved characters. ]

因此,C++ 认为 cout 足够 thread-safe,尽管事实上它具有可能导致交错字符的逻辑竞争条件。相比之下,Microsoft 认为它 thread-safe 不足以达到他们的目的,并增加了针对这种竞争条件的保护。

所以这就是为什么我认为“thread-safe”是主观的,而 context-dependent,而竞争条件可以更 objective 明确地决定你是否想要处理还是不处理