如何在java中重现竞争条件?
我试图创造一个这样的比赛条件如何在java中重现竞争条件?,java,multithreading,Java,Multithreading,我试图创造一个这样的比赛条件 class Bankaccount { private int balance=101; public int getBalance(){ return balance; } public void withdraw(int i){ balance=balance-i; System.out.println("..."+balance); } } public class
class Bankaccount {
private int balance=101;
public int getBalance(){
return balance;
}
public void withdraw(int i){
balance=balance-i;
System.out.println("..."+balance);
}
}
public class Job implements Runnable{
Bankaccount b=new Bankaccount();
public void run(){
if(b.getBalance()>100){
System.out.println("the balanced ammount is"+b.getBalance());
/*try{
Thread.sleep(9000);
}
catch(Exception e){
}*/
makeWithdrawl(100);
}
}
public void makeWithdrawl(int ammount){
b.withdraw(ammount);
System.out.println(b.getBalance());
}
public static void main(String[] args) {
Job x=new Job();
Job y=new Job();
Thread t1=new Thread(x);
Thread t2=new Thread(y);
t1.start();
t2.start();
}
}
我得到了输出:
平衡的弹药是101
1.
1.
平衡的弹药是101
…1
我原以为会是负数,因为100人中有两次退出
这里少了什么?提前感谢您的代码无法创建比赛条件,但这里有一些信息供您参考 可靠地再现竞争条件将非常困难,因为多线程程序本质上是不确定的。这意味着独立线程中的独立命令的执行顺序没有固定顺序 本次讨论提供了一些关于该主题的好信息: 我认为您在示例中的意思是,您希望在线程在其上执行后,余额被计算为具有特定值。要做到这一点,您必须使用锁来确保一次只有一个线程访问相关变量 锁确保在其他线程操作该值时尝试读取该值的任何线程必须等到操作该变量的线程完成后,才能读取和使用该变量本身 您将需要锁来完成您在示例中尝试执行的操作
- 这是关于使用锁保护的官方文档 变量,它包括一个小示例
- 这个讨论很好地回答了锁的使用问题 在爪哇
// This class exposes a publicly accessible counter
// to help demonstrate data race problem
class Counter {
public static long count = 0;
}
// This class implements Runnable interface
// Its run method increments the counter three times
class UseCounter implements Runnable {
public void increment() {
// increments the counter and prints the value
// of the counter shared between threads
Counter.count++;
System.out.print(Counter.count + " ");
}
public void run() {
increment();
increment();
increment();
}
}
// This class creates three threads
public class DataRace {
public static void main(String args[]) {
UseCounter c = new UseCounter();
Thread t1 = new Thread(c);
Thread t2 = new Thread(c);
Thread t3 = new Thread(c);
t1.start();
t2.start();
t3.start();
}
}
并尝试使用此代码来修复它
public void increment() {
// increments the counter and prints the value
// of the counter shared between threads
synchronized(this){
Counter.count++;
System.out.print(Counter.count + " ");
}
}
此代码片段摘自SG Ganesh,Tushar Sharma编写的《Oracle认证专业Java SE 7程序员考试1Z0-804和1Z0-805》一书,其中有几点您需要了解 1) 您的特定系统上的特定JVM可能不受您试图在此处复制的竞争条件的影响。
2) 你不太可能在一次跑步中再现比赛状态。它被认为是不确定的,如果它给出一致的结果,它将不是一个竞争条件,而是一个错误。为了提高您的机会,请进行自动健全性检查,并运行代码10万次。 3) 使用内存屏障使两个线程同时启动会增加出现争用情况的机会。使用多核系统也有帮助。
4) 您的代码无论如何都无法生成竞争条件。仔细观察-每个作业都使用自己的帐户。对于竞态条件,您需要共享状态。当多个线程更改共享数据时,会出现竞态条件。在您的示例中,每个线程都有自己的Bankaccount类。您需要将其共享,如下所示:
class Job implements Runnable{
Bankaccount b;
Job(Bankaccount b){
this.b = b;
}
public void run(){
if (b != null)
if(b.getBalance()>100){
System.out.println("the balanced ammount is " + b.getBalance());
makeWithdrawal(100);
}
}
public void makeWithdrawal(int ammount){
b.withdraw(ammount);
System.out.println(b.getBalance());
}
public static void main(String[] args) {
// Creating one Bankaccount instance
Bankaccount b = new Bankaccount();
// Passing one instance to different threads
Job x=new Job(b);
Job y=new Job(b);
Thread t1=new Thread(x);
Thread t2=new Thread(y);
// Race conditions may appear
t1.start();
t2.start();
}
}
不幸的是,这还不够。多线程程序是不确定的,您可以在多次执行程序后收到不同的结果。例如,线程t1可以在线程t2开始检查余额之前进行取款。因此,t2不会因为资金不足而进行取款
为了增加负余额的可能性,您可以在检查余额和取款之间插入延迟 您没有给线程足够的时间来满足竞争条件。这也可能在任何时候发生。println()语句也会大大降低速度。每个线程(作业)都使用自己的
BankAccount
实例,因此我无法在这里创建竞态条件。我将run()中的所有代码放入synchronized(此),但仍然得到相同的结果?而不是“复制”,说“演示”“。建立数据竞赛很容易。你可以在文献和网络上找到很多例子。最困难的部分是证明比赛的结果并不总是一样的。当我必须在我公司的生产代码中演示一个数据竞赛时,我运行了1000万次实验,结果只出现了不到100次的错误。此外,我想我应该注意,如果给每个线程提供其自己的Bankaccount实例,那么两个线程都必须使用相同的Bankaccount实例,正如前面提到的,你无法获得竞争条件,@Rajesh,正如用户“home”在对你的问题的评论中指出的那样,如果你一直将x传递给一个线程,将y传递给另一个线程,那么两个线程都无法访问同一个银行帐户。你需要让他们使用同一个银行account@james大体上,您认为建立数据竞争很容易,这是正确的。确定结果是困难的部分。然而,OP似乎在问是什么导致“比赛条件再次发生”,所以我使用了复制