任何人都可以向我解释什么是竞争条件,如何避免它,以及如何在java代码中找到它?
好的,我只知道几天的“竞争状况”,我有两个例子,也许它们不够好,这就是为什么我需要你的帮助:)希望你们中的任何人都可以为我解释。
例1: 检查然后行动:
if(vector.contains(e))//check
{
vector.remove(e)
}
如果有2个线程可以访问,则thread1在检查向量包含e之后挂起,而e在向量中挂起,然后thread2访问检查然后从向量中删除e,然后thread1返回并执行删除操作,将发生错误,因为e已经被thread2删除了。
例2: 读修改写:
假设我们在方法中有一个计数器变量,一旦调用该方法,计数器增加1,
counter++
这不是原子操作,它有3个步骤: 得到价值 2.增加价值 3.分配值
我对种族状况的了解就在这里,希望你能与我分享你的知识:)
感谢
答案 0 :(得分:3)
什么是比赛条件? 检查此堆栈溢出question。
竞争条件主要有两种情况:read-modify-write和check-then-act。
对于read-modify-write,经典示例是counter++
,它不是原子操作,因此导致竞争条件。
对于check-then-act,有多个例子。一个例子是当你在ConcurrentHashMap中检查密钥存在然后在if-case中做一些工作。另一个例子是单例类代码:
public Singleton getInstance()
{
if(_instance == null)
{
_instance = new Singleton();
}
}
您可以在互联网上阅读更多相关信息。一本关于并发性的好书是Brian Goetz的Java Concurrency in Practice。您也可以找到这个article有帮助。
答案 1 :(得分:2)
来自Java Concurrency in Practice book
“当计算的正确性发生竞争条件时 取决于多个线程的相对时间或交错 运行时;换句话说,当得到正确的答案依赖 幸运时间“
竞争条件最常见的条件是check-then-act,其中使用可能安全的观察来决定下一步该做什么。
如果没有种族条件的另一个常见条件
对于你的例子1。
if (!vector.contains(element))
vector.add(element);
即使包含和添加是原子的,这种在put-if-absent操作中的尝试也有竞争条件。虽然同步方法可以使单个操作成为原子,但还需要额外的锁定 - 当多个操作组合成复合操作时。
答案 2 :(得分:1)
答案中提供的示例:" read-modify-write"和" check-then-act"是不够来定义竞争条件的情况。
如果您了解竞争条件'作为由两个或多个线程以不确定的顺序访问共享内存而导致不可预测结果的条件,其中至少有一个访问用于写入,然后(a)您不需要同时拥有两个'读'并且'写'在同一个线程中。
(b)变量的原子定义也不能使我们免于竞争条件的潜力。如果一个线程在另一个线程从其读取之前写入原子变量并且访问没有正确排序,则结果仍然是不可预测的。您可以看到对此点的进一步说明here。