Question

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

Was it helpful?

Solution

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.

OTHER TIPS

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.

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


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

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top