在编写多线程应用程序时,遇到的最常见的问题之一是竞争条件。
我对社区的问题是:
竞态条件是什么? 你如何发现它们? 你是如何处理的? 最后,你如何防止它们的发生?
在编写多线程应用程序时,遇到的最常见的问题之一是竞争条件。
我对社区的问题是:
竞态条件是什么? 你如何发现它们? 你是如何处理的? 最后,你如何防止它们的发生?
当前回答
我做了一个视频来解释这个。
从本质上讲,它是当你有一个跨多个线程共享的状态,在一个给定状态的第一次执行完成之前,另一个执行开始,一个给定操作的新线程的初始状态是错误的,因为前一次执行还没有完成。
由于第二次执行的初始状态是错误的,因此计算结果也是错误的。因为最终第二次执行会用错误的结果更新最终状态。
你可以在这里查看。 https://youtu.be/RWRicNoWKOY
其他回答
竞态条件是一种bug,只会在特定的时间条件下发生。
例子: 假设您有两个线程,A和B。
在线程A中:
if( object.a != 0 )
object.avg = total / object.a
线程B:
object.a = 0
如果线程A在检查完对象后被抢占。a不为空,B将执行a = 0,当线程a将获得处理器时,它将执行“除零”。
这个错误只发生在if语句之后的线程A被抢占时,这是非常罕见的,但它是有可能发生的。
考虑一个操作,该操作必须在计数增加时立即显示计数。ie。,只要CounterThread增加值,DisplayThread就需要显示最近更新的值。
int i = 0;
输出
CounterThread -> i = 1
DisplayThread -> i = 1
CounterThread -> i = 2
CounterThread -> i = 3
CounterThread -> i = 4
DisplayThread -> i = 4
在这里,CounterThread频繁地获取锁,并在DisplayThread显示它之前更新值。这里存在一个竞态条件。竞争条件可以通过使用同步来解决
您并不总是希望丢弃竞态条件。如果你有一个可以被多个线程读写的标志,并且这个标志被一个线程设置为“done”,这样当标志被设置为“done”时,其他线程就会停止处理,你不希望这个“竞争条件”被消除。事实上,这可以被称为良性竞态条件。
然而,使用检测竞态条件的工具,它将被视为有害的竞态条件。
更多关于比赛情况的详细信息,请访问http://msdn.microsoft.com/en-us/magazine/cc546569.aspx。
什么是竞态条件?
You are planning to go to a movie at 5 pm. You inquire about the availability of the tickets at 4 pm. The representative says that they are available. You relax and reach the ticket window 5 minutes before the show. I'm sure you can guess what happens: it's a full house. The problem here was in the duration between the check and the action. You inquired at 4 and acted at 5. In the meantime, someone else grabbed the tickets. That's a race condition - specifically a "check-then-act" scenario of race conditions.
你如何发现它们?
宗教代码审查多线程单元测试没有捷径。在此基础上出现了一些Eclipse插件,但还没有稳定的插件。
你如何处理和预防它们?
最好的方法是创建无副作用和无状态的函数,尽可能使用不可变函数。但这并不总是可能的。使用java。util。concurrent。原子的、并发的数据结构、适当的同步和基于参与者的并发将有所帮助。
并发性的最佳资源是JCIP。你也可以在这里得到更多关于上述解释的细节。
当两个或多个线程可以访问共享数据,并且它们试图同时更改数据时,就会发生竞态条件。因为线程调度算法可以在任何时候在线程之间交换,所以您不知道线程将尝试访问共享数据的顺序。因此,数据更改的结果依赖于线程调度算法,即两个线程都在“竞相”访问/更改数据。
当一个线程执行“检查-然后-行动”时,问题经常发生。“check”如果值是X,那么“act”做一些取决于值是X的事情),另一个线程在“check”和“act”之间对值做一些事情。例句:
if (x == 5) // The "Check"
{
y = x * 2; // The "Act"
// If another thread changed x in between "if (x == 5)" and "y = x * 2" above,
// y will not be equal to 10.
}
这一点是,y可以是10,也可以是任何值,这取决于在检查和执行之间是否有另一个线程改变了x。你根本不知道。
为了防止竞争条件的发生,您通常会在共享数据周围放置一个锁,以确保一次只有一个线程可以访问数据。这意味着:
// Obtain lock for x
if (x == 5)
{
y = x * 2; // Now, nothing can change x until the lock is released.
// Therefore y = 10
}
// release lock for x