Homework 5 Version 0 |
|
👤 Author: by shatino94163com 2020-12-22 05:45:52 |
Describe your own case which encounters data inconsistency when processes share data, and write the method to solve the problem.
Problem: The Bankers Dilemma
A bank transaction might be a good example, both because it's easy to see that an incorrect result is bad and because race conditions are easy to create in such an environment.
I have ¥500 on my account. Someone transfers ¥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 transactions 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. Clerk 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 'threads 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 happens in the order shown above. That should relate it to the specific problems 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 also be achieved using other synchronization constructs like locks or atomic variables like java.util.concurrent.atomic.AtomicInteger.
Code Example:
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
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 TransactionManagerNaiveSync implements Runnable {
Account account;
public TransactionManagerNaiveSync(Account a){
this.account = a;
}
public static void main(String[] args) {
long start = System.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 = System.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.deposit(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 withdrawal : "+account.getBal());
//}
}
}