java - 竞争条件 : from harmful to harmless

标签 java concurrency

<分区>

我从 everything2.com 中采用了竞争条件的定义如下:

A race condition is a situation where running multiple concurrent processes (for these purposes, a thread is also modeled as a process, as are processes running on separate machines) will give differing results, depending on the (unspecified, and usually unspecifiable) details of the ordering of operations.

现在考虑以下来自 Chapter 3: Race Conditions and Mutual Exclusion 的示例:

The most dangerous race conditions, however, involve access to shared data structures. If two threads are updating the same data structure at the same time, the changes may be made partially by one thread and partially by the other. The contents of the data structure can then become garbled, which will confuse threads that access it later, thereby causing them to crash.

显然,此示例包含有害的竞争条件。

有一个解决方案可以避免这种有害的竞争条件:

The trick is to force the threads to access the data structure one at a time, so called mutual exclusion, so that each thread can complete its update and leave the structure in a consistent state for the next thread.

现在根据上面的定义,上面的解决方案中仍然存在竞争条件:

If thread A makes change first, then final content of shared data structure is filled by thread B; if thread B makes change first, then final content of shared data structure is filled by thread A.

但现在它是一个无害的竞争条件。

从这个示例中,我得到以下结论:

A race condition is harmful if and only if it is avoidable.

我不确定上述结论是双向的还是只有一个方向是正确的还是不正确的。那么有没有样本可以反驳这个结论呢?

最佳答案

你是对的。

竞争条件 - 当多个线程访问相同的资源时出现。
导致竞争条件的代码段称为临界区。 请注意,当我们试图避免竞争条件时会发生死锁。

您可以通过创建线程安全代码来避免竞争条件。

  • 局部变量。

    局部变量存储在每个线程自己的栈中。这意味着局部变量永远不会在线程之间共享。

  • 本地对象引用。

    所有对象都存储在共享堆中,但如果在本地创建的对象永远不会逃脱创建它的方法,那么它就是线程安全的。

  • 使成员字段可变、最终和私有(private)。

但是如果你想共享一个变量并且仍然以同步方式控制它的访问。您可以通过以下方式做到这一点,

  • 使用显式锁(和条件变量)
  • 使用同步(隐式锁)

这仍然不能保证哪个线程先访问哪个线程。 对于这种对线程的控制,请使用信号。

它可以通过多种方式实现。

  • 通过共享对象发出信号
  • 忙等
  • wait()、notify() 和 notifyAll()
  • 错过的信号
  • 虚假唤醒

关于java - 竞争条件 : from harmful to harmless,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12189578/

相关文章:

java - 将自定义作业添加到作业执行器

java - 以下 Java 绘画代码在 Android 中的等价物是什么?

c# - 如何避免 RCW 清理上的竞争

java - 并发使用 JaxWsPortProxyFactoryBean

java - ScheduledThreadPoolExecutor + setXXXXShutdownPolicy()

c++ - std::async 如何工作:为什么它多次调用复制/移动?

java - Akka变得()和getSender()不兼容

java - 为什么 URL 中的正斜杠会导致对 Stripes Action Bean 的无限循环调用?

java - FileInputStream 是否已经在使用缓冲区?

Java:如何通过 ArrayList 中的新行读取它们并将其存储在数组中?