如何在java中重现竞争条件?

时间:2014-05-15 16:05:35

标签: 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 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();
    }

}

我得到输出: 平衡的ammount是101 1 ... 1 平衡的ammount是101 ... 1

我原以为它是负面的,因为100次退出发生了两次

这里缺少什么?在此先感谢

4 个答案:

答案 0 :(得分: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不会退出。

为了增加负余额的可能性,您可以在检查余额和取款之间插入延迟。

答案 1 :(得分:-1)

您的代码无法创建竞争条件,但这里有一些信息。

重现竞争条件可靠将很难做到,因为多线程程序本质上是非确定性的。这意味着对独立线程中的独立命令执行的顺序没有高兴的命令。

这个讨论有关于这个主题的一些很好的信息:

Can a multi-threaded program ever be deterministic?

我认为您在示例中的意思是,您希望在执行线程后对余额进行操作以获得特定值。为此,您必须使用锁以确保唯一的一个线程一次访问相关变量。

一个锁确保在某个其他线程正在操作它时尝试读取该值的任何线程必须等到操作该变量的线程完成然后才能读取并使用该变量本身。

您需要使用锁来执行您在示例中要执行的操作


答案 2 :(得分:-1)

尝试此代码以生成竞争条件

// 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”

答案 3 :(得分:-1)

您需要了解几件事情。

1)您特定系统上的特定JVM可能不受您在此处尝试重现的竞争条件的影响 2)单次跑步不可能重现比赛条件。它的假定是非确定性的,如果它给出了一致的结果,它就不会成为竞争条件,而是一个错误。为了提高您的机会,进行自动完整性检查并运行代码100k次。 3)使用内存屏障使两个线程同时启动会增加竞争条件发生的可能性。使用多核系统也有帮助。 4)无论如何,你的代码不能产生竞争条件。仔细观察 - 每项工作都使用它自己的帐户。对于竞争条件,您需要共享状态。