Anonymous
Anonymous

Reputation: 471

Running Threads One at a Time (Instead of Parallel)

This is the same code as a previous question I had asked but addressing a different issue. Essentially I am trying to make a bank account with two threads, each representing a user of the account. The users will deposit and withdraw 20$ from the account (randomly).

However, both these threads run in parallel, and the withdraw/deposit happen at the same time. I am trying to limit both threads such that it waits for the other thread to finish before executing its own run method.

Listed below is the code.

Thread creation class

import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;

public class BankAccount extends Thread{
public static double balance = 1000;
public String threadName;

BankAccount(String name){
    threadName = name;
}
public void run(){
    System.out.println(threadName + "account initiated.");
    for(int i = 0; i < 10; i++){
        try{
            Random rand = new Random();
            int num = rand.nextInt(2) + 1;
            if(num == 1){
                Thread.sleep(200); //0.2 seconds to deposit
                System.out.println(threadName + " is depositing 20$ in the bank.");
                balance += 20;
                System.out.println("The new balance is " + balance + "dollars" );
            }
            else{
                Thread.sleep(500); //half a second to withdraw
                System.out.println(threadName + " is withdrawing 20$ from the bank.");
                balance -= 20;
                System.out.println("The new balance is " + balance + "dollars.");
                }
        }
        catch(InterruptedException e){
            System.out.println("Process terminated.");
            }
        }
    }
}

Thread Driver Class

public class BankAccountSimDriver {
    public static void main(String[] args){
    Thread user1 = new BankAccountSIm("user1"); 
    Thread user2 = new BankAccountSIm("user2");

    user1.start();
    user2.start();
    }
}

The output currently:

user1 initiated.
user2 initiated.
user1 is depositing 20$ in the bank.
user2 is depositing 20$ in the bank.
The new balance is 1020.0 dollars
The new balance is 1040.0 dollars
user2 is depositing 20$ in the bank.
The new balance is 1060.0 dollars
user1 is withdrawing 20$ from the bank.
The new balance is 1040.0 dollars.

Currently, user1 and user2 run at the same time. I'd like to edit the code such that only one user can deposit/withdraw at a time (indicated by the sleep() time separation)

So the ideal output:

user1 initiated.
//wait 0.2 seconds
user1 is depositing 20$ in the bank.
The new balance is 1020.0 dollars
user2 initiated.
//wait 0.2 seconds
user2 is depositing 20$ in the bank.
The new balance is 1040.0 dollars
//wait 0.5 seconds
user1 is withdrawing 20$ from the bank.
The new balance is 1020.0 dollars.
...

Upvotes: 1

Views: 287

Answers (1)

Jean-Baptiste Yun&#232;s
Jean-Baptiste Yun&#232;s

Reputation: 36401

What you need is to manage concurrent accesses to balance, not to serialize threads, at least you need to serialize accesses to balance. There is a lot of ways to tackle it. Basically, you need a lock that should be used to let only one thread doing modification of the balance, the other being blocked until the other release the lock.

First you need to separate BanckAccount and users of it.

class BankAccount { ... }

class User implements Runnable {
    private BankAccount account;
    public User(BankAccount account) {
         this.account = account;
    }
    public void run() {
      // do something...
    }
}

class Test {
    public static void main(String []a) {
        // One account
        BankAccount a = new BankAccount();
        // Shared by 2 users
        User user1 = new User(a);
        User user2 = new User(a);
        // Make users behave concurrently
        Thread t1 = new Thread(user1);
        Thread t2 = new Thread(user2);
        t1.start();
        t2.start();
        // Wait 'til the end of the users activity
        t1.join();
        t2.join();
    }
}

Now how to manage concurrent accesses of the same bank account from users ? You can use the BankAccount object as an implicit lock by making BankAccount methods synchronized:

class BankAccount {
    private int balance;
    public BankAccount(int initialBalance) {
        balance = initialBalance;
    }
    public synchronized int deposit(int amount) {
        balance += amount;
        return balance;
    }
    public synchronized int withdraw(int amount) {
        balance -= amount;
        return balance;
    }
}

Doing so ensures that no two threads can be at the same time inside methods marked synchronized, thus no two threads can modify the balance at the same time.

But... (concurrency leads to subtle problems)... it may happens that each threads use a cached copy of balance so it is in general more appropriate to mark that field as volatile:

private volatile int balance;

Note, that in such simple situation some things may be simplified, but I tried to show you what are the problems and how you can solve them. Also note, that even this code may lead to strange outputs, but the guaranty is that the balance is correct (dig on concurrency, now).

Upvotes: 2

Related Questions