2019529628006_John Nagbe Kofa_HW5 Version 0 |
|
👤 Author: by meekkofaoutlookcom 2021-10-20 03:14:01 |
Describe your own case which encounter data inconsistency when processes share data and write the method to solve that problem.
Problem: The Bankers Dilemma
I have $500 on my account, someone transfer $200 to me at the same time that I withdraw $50. Now, if the bank doesn’t handle race conditions properly, they will do the following (assuming the transaction are handled manually, of course) Clerk A will see the request to add $200 to my balance and note that my balance is currently $500, Clark B will see the request to subtract $50 from my balance and note that my balance is currently $500 (clerk A hasn’t yet transferred the money). Clerk A finishes the paperwork and sets my account balance to $700 (500 + the 200 he was supposed to add). And then, a minute later (because clerk B just had to grab a cup of coffee), Clerk B finishes up the other transaction and sets my balance to $450 (the 500 I had when he checked, minus the 50 he was meant to subtract). My balance is now $450, when it should have been $650, because of a race condition.
The outcome depended on the order in which different parts of the two transactions were performed. That’s the general descr iption of how race conditions are bad. Now say that instead of clerks, we have our application processing two separate tasks at the same time (that’s your ‘thread of execution’), and just like above, they both read a value, modify the value that they read, and then write it back. One of the modifications may then be lost if this happen in the order shown above. That should relate it to the specific problem in your app.
Solution
Race conditions can be avoided by proper thread synchronization in critical sections. Thread synchronization can be achieved using a synchronized block of java code. Thread synchronization can be achieved using other synchronization constructs like locks or atomic variables like java.util.concurrent.atomic.AtomicInterger.
Code Example
package com.company;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import static java.lang.System.*;
public class Main {
public static void main(String[] args) {
class Account {
private int balance = 0;
Account(int bal) {
this.balance = bal;
}
public int getBal() {
return balance;
}
public synchronized void withdraw(int bal) {
balance = balance - bal;
}
public synchronized void deposit(int bal) {
balance = balance + bal;
}
}
public class TransactionManagerNaiveSyn implements Runnable {
Account account;
public TransactionManagerNaiveSync(Account a) {
this.account = a;
}
public static void main(String[] args) {
long start = currentTimeMillis();
Account a1 = new Account(500);
TransactionManagerNaiveSync t1 = new TransactionManagerNaiveSync(a1);
List<Thread> thread = new ArrayList<Thread>();
for (int i = 0; i < 300; i++) thread.add(new Thread(t1));
for (int i = 0; i < 300; i++) thread.get(i).start();
for (int i = 0; i < 300; i++) {
try {
thread.get(i).join();
} catch (interruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
long end = currentTimeMillis();
System.out.println("Account Balance in the end:" +a1.getBal());
System.out.println("Time Taken:" +(end - start));
}
@Override
public void run() {
//for(int i=0; i<100; i++)
//{
account.deposite(10);
System.out.println(""+ Thread.currentThread().getId() +"Account Balance after deposit:" +
account.getBal());
try {
thread.sleep(100);
} catch (interruptedException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
account.withdraw(10);
System.out.println(""+Thread.currentThread().getId() +"Account Balance after withdraw:"
+account.getBal());
//}
}
}
}
}