0

I tried to create a race condition like this.

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

}

I am getting output: the balanced ammount is101 ...1 1 the balanced ammount is101 ...1

I was expecting it to be in negative as two times withdrawal happened for 100

What is missing here? Thanks in Advance

Rajesh
  • 87
  • 1
  • 9
  • You're not giving enough time to the threads to go for the race condition. It may happen in any moment, too. – Luiggi Mendoza May 15 '14 at 16:07
  • the println() statements are going to be slowing things down considerably as well. – Marc B May 15 '14 at 16:08
  • 2
    Each thread (Job) uses its own instance of `BankAccount` so I cannot see any way to create a race condition here. – home May 15 '14 at 16:13

4 Answers4

4

Race conditions appear when multiple threads change shared data. In your example each thread has its own Bankaccount class. You need to make it shared, like this:

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

}

Unfortunately, this is not enough. Multithreaded programs are non deterministic and you can receive different results after several executions of the program. For example, thread t1 can manage to make withdrawal before thread t2 started to check the balance. Hence, t2 will not do withdrawal due to the lack of money.

To increase the likelihood of negative balance you can insert delay between checking the balance and withdrawing money.

Andrey Sozykin
  • 926
  • 12
  • 13
0

There are several things you need to understand about this.

1) Your particular JVM on your particular system may be impervious to race conditions you are trying to reproduce here.
2) You are not likely to reproduce a race condition with a single run. It's supposed to be non-deterministic, if it gave consistent results it wouldn't be a race condition, but rather an error. To improve your chances make an automated sanity check and run the code 100k times. 3) Using memory barriers so that both threads start at the same time increases the chances a race condition will occur. Using a multi-core system helps too. 4) Your code cannot produce a race condition anyway. Look closely - each job is using it's own account. For a race condition you need shared state.

Ordous
  • 3,844
  • 15
  • 25
-1

Your code cant create a race condition, but here is some information for you.

Reproducing a race condition reliably is going to be really hard to do because multi threaded programs are inherently non-deterministic. This means that there is no gaurunteed order to the order in which independent commands in independent threads execute.

This discussion has some good information on the topic:

Can a multi-threaded program ever be deterministic?

What I think you mean in your example, is that you want the balance to be garunteed to have a specific value after a thread executes on it. To do that, You will have to use locks to make sure the only one thread accesses the variable in question at a time.

A lock makes sure that any thread which attempts to read that value while some other thread is manipulating it, must wait until the thread manipulating the variable completes before it can then read and use the variable itself.

You will need locks to do what you are trying to do in your example


Community
  • 1
  • 1
VampyreSix
  • 101
  • 3
  • I put all the code inside run() into synchronized(this), still i am getting same result? – Rajesh May 15 '14 at 16:34
  • Instead of "reproducing", say "demonstrating". It's easy to set up a data race. You can find lots of examples in literature and on the web. The hard part is demonstrating that the outcome of the race is not always the same. When I had to demonstrate a data race in my company's production code, I ran the experiment ten million times, and it only came out the wrong way less than one hundred times. – Solomon Slow May 15 '14 at 16:34
  • Also I guess I should note that you would have to use the same instance of Bankaccount for both threads, if you give each thread its own instance of bankaccount, like was mentioned, you cant get the race condition, – VampyreSix May 15 '14 at 16:34
  • @Rajesh, as the user 'home' has pointed out in the comments on your question, if you keep passing x to one thread and y to the other, neither thread will get access to the same bank account. You need to make them use the same bank account – VampyreSix May 15 '14 at 16:36
  • @james large, You are correct in that setting up a data race is easy. Determining the outcomes is the hard part. However, the OP seemeed to be asking what makes a "race condition happen again" so i used reproduce – VampyreSix May 15 '14 at 16:38
-1

try this code to generate a race condition

// 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();
    }
}

and try this code to fix it

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 + " ");
    }
}

this code snippet is from the book "Oracle Certified Professional Java SE 7 Programmer Exams 1Z0-804 and 1Z0-805" written by SG Ganesh, Tushar Sharma

Leo
  • 6,480
  • 4
  • 37
  • 52