Showing posts with label thread collision. Show all posts
Showing posts with label thread collision. Show all posts

Tuesday, 8 April 2014

Example of race condition in java multithreading

Race Condition:


Race condition occurs, when 2 or more threads try to access the shared data of same program and try to change it.  In java, the shared data may be the instance variables because for method variables, each thread has it's own copy.

Example:


package thread;

/**
* @author Sivaranjani D
*
*/
public class MultiThreadsDanger {

public static void main(String[] args) {
Runnable atm = new ATM();
Thread withdrwer1 = new Thread(atm);
withdrwer1.setName("withdrawer1");
withdrwer1.start();

Thread withdrwer2 = new Thread(atm);
withdrwer2.setName("withdrawer2");
withdrwer2.start();
}

}

class Account {
int balance = 500;

public void debit(int amount) {
balance = balance - amount;
}

public void credit(int amount) {
balance = balance + amount;
}

public int getBalance() {
return balance;
}
}

class ATM implements Runnable {
Account account = new Account();

public void run() {
for (int i = 0; i < 5; i++) { if (account.getBalance() > 0) {
makeWithdrawal(100);
} else {
System.out.println("Not enough in amount for "
+ Thread.currentThread().getName() + " to withdraw ");
}

}
}

private void makeWithdrawal(int amt) {
if (account.getBalance() >= amt) {
System.out.println(Thread.currentThread().getName()
+ " cheked balance and the balance is :"
+ account.getBalance());

account.debit(amt);
System.out.println(Thread.currentThread().getName()
+ " completes the withdrawal and the balance: "
+ account.getBalance());
}
}

}

Output
withdrawer1 cheked balance and the balance is :500
withdrawer1 completes the withdrawal and the balance: 400
withdrawer2 cheked balance and the balance is :400
withdrawer2 completes the withdrawal and the balance: 300
withdrawer2 cheked balance and the balance is :300
withdrawer2 completes the withdrawal and the balance: 200
withdrawer2 cheked balance and the balance is :200
withdrawer2 completes the withdrawal and the balance: 100
withdrawer2 cheked balance and the balance is :100
withdrawer2 completes the withdrawal and the balance: 0
Not enough in amount for withdrawer2 to withdraw
Not enough in amount for withdrawer2 to withdraw
Not enough in amount for withdrawer2 to withdraw
Not enough in amount for withdrawer2 to withdraw
Not enough in amount for withdrawer2 to withdraw
Not enough in amount for withdrawer2 to withdraw
withdrawer1 cheked balance and the balance is :400
withdrawer1 completes the withdrawal and the balance: -100
Not enough in amount for withdrawer1 to withdraw
Not enough in amount for withdrawer1 to withdraw
Not enough in amount for withdrawer1 to withdraw
Not enough in amount for withdrawer1 to withdraw
Not enough in amount for withdrawer1 to withdraw
Not enough in amount for withdrawer1 to withdraw
Not enough in amount for withdrawer1 to withdraw
Not enough in amount for withdrawer1 to withdraw

Explanation:



  1. The file has an account class, which has some methods to credit, debit and get balance

  2. There is a ATM class which implements runnable. This ATM has the account and it's run method has the provision to call withdrawal method

  3. In the main class, we have created 2 threads by passing the same ATM object. So both the threads are considered as a 2 with-drawers . Both the threads now calls the run method of same ATM object and both the threads runs in the same run block.

  4. Even though we are doing the balance check in the above program, the output shows -100. How this is happening??

  5. The reason is, the atomic operations are not accessed by a single thread. In the above program atomic operation is, checking the balance and debit (inside withdrawal method). For example, consider the account has a balance of 100. And think now the first thread is doing the balance check. That means it executes the line if (account.getBalance() >= amt) . Now it succeeds in this line because we have 100 as balance and the amt to be debited is also 100. So next it will call the account.debit(amt); But as we know thread scheduler may stop this thread before executing the debit step and save it's state. Now, the second thread comes and it does the same first step. This also succeeds,  because still the first thread has not debited. so the second thread also calls the second statement. It debits the amount and balance will becomes zero. Since the second thread finished its job it will die. Now the thread scheduler may again resumes the first thread, which was stopped after balance check. So now the first thread starts from where it paused. That means it start with the debit. So now we will get the -100 as output.


This situation is called as race condition.

Thursday, 3 April 2014

What is Thread collision and how to avoid it in java?

What is Thread Collision?


In a multi-threaded environment, multiple threads will be running in the same method/block of the program. This is called thread collision and it can cause significant effect in the program.  Thread collision leads to race condition.

For example, considered the below program.
The program has a class named ThreadIncrementer ,which implements the Runnable interface. It's run method increments numbers from 1 to 50; And we have created 3 Threads by passing the  runnable object. So each threads will be running the same run method of the ThreadIncrementer class.

Code:
package thread.assignment;

/**
* @author Sivaranjani D
*
*/
public class ThreadIntor {
public static void main(String[] args) throws InterruptedException {
ThreadIncrementer threadIncrementer = new ThreadIncrementer();
Thread t1 = new Thread(threadIncrementer);
Thread t2 = new Thread(threadIncrementer);
Thread t3 = new Thread(threadIncrementer);
t1.start();
t2.start();
t3.start();

t1.join();
t2.join();
t3.join();
System.out.println(threadIncrementer.normalnumber);
}

}

class ThreadIncrementer implements Runnable {
int normalnumber = 0;

public void run() {
for (int i = 0; i < 50; i++) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
normalnumber++;
}
}
}

Output:
142

The expected output for the above program should be 150. Because the loop will increment normalnumber for 50 and there are 3 threads running. So 3*50 = 150.
But, you don't get the same 150 all the time. That is because of multiple threads collision in the same block.

How Thread collision creates the above problem?


In the above example, take a look at the code normalnumber++. This might look like a single line of code. But it is not.
Generally there are 3 tasks happens inside.

  1. Read the old value of normalnumber

  2. Increment the normalnumber

  3. Reassign the incremented value to normalnumber


Consider now, there 2 threads coming into the block to increment normalnumber. And consider the old value of normalnumber is 5

  • The first thread performs the step 1, and reads the value of normalnumber as 5 and goes to the step 2.

  • Before the first thread increments the value, the second thread also reads the old value of normalnumber as 5.

  • Now, consider the first thread incremented normalnumber to 6 and reassigned the value

  • But since Second Thread also has read the same old value as 5, it will also does the same job what First Thread does.

  • Now we are missing one increment. After 2 increment the value of normalnumber should be 7. Instead we are getting only 6.


In the above program, it may not look serious. But think about the account overdraw by 2 threads, which is a serious issues.

So please make design consideration and follow the below ways to avoid collision in the multi-threaded environment.

Different ways to avoid thread collision: