Multi Threading banking simulation

1.9k Views Asked by At

At this moment I'm playing around with Multi Threading in java and I'm not sure how this works.. I feel like I understood this in a simple example I've seen on the internet but somehow I can't understand how this works in a banking simulation app I found and modified from the internet.

Here's what I have:

Person class:

package threadsproject;

public class Person {

    private String name;

    public Person(String name){
        this.name = name;
    }

    public String getName(){
        return name;
    }

    public void setName(String name){
        this.name = name;
    }
}

Account class:

package threadsproject;

public class Account {

    public static int balance;
    public static Account acc;
    private static Person p;

    public static int getBal(){
        return balance;
    }

    public void setBal(int bal){
        Account.balance = bal;
    }

    public static Account getAcc(Person p){
        if(acc == null){
            acc = new Account();
        }
        Account.p = p;
        return acc;

    }

    public synchronized void deposit(int val){
        try{

            if(val > 0){
                System.out.println("Person "+p.getName()+" is making a deposit.");
                try{
                    Thread.sleep(500);
                }catch(Exception e){}
                balance = balance + val;
                System.out.println("Person "+p.getName()+" completed the deposit.");
            }else{
                System.out.println("Can't deposit.");
            }
            System.out.println("Person "+p.getName()+" deposited "+val);

        }catch(Exception e){}
    }

    public synchronized void withdraw(int val){
        try{

            if(balance >= val){
                System.out.println("Person "+p.getName()+" is making a withdraw.");
                try{
                    Thread.sleep(500);
                }catch(Exception e){}
                balance = balance - val;
                System.out.println("Person "+p.getName()+" completed the withdraw.");
            }else{
                System.out.println("Can't withdraw.");
            }
            System.out.println("Person "+p.getName()+" withdrew "+val);

        }catch(Exception e){}
    }

}

Thread Class:

package threadsproject;

import java.util.Scanner;

public class BankThread extends Thread implements Runnable{

    private Person p;

    public BankThread(Person p){
        this.p = p;
    }

    public void run(){
        for (int i = 0; i < 3; i++) {
            try {
                Account acc = Account.getAcc(p);
                Scanner s = new Scanner(System.in);
                System.out.println("Enter deposit ammount:");
                int dep = s.nextInt();
                acc.deposit(dep);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException ex) { }

                System.out.println("Enter withdrawal ammount:");
                int with = s.nextInt();
                if(with > Account.getBal()){
                    System.out.println("You don't have enough funds.");
                }else{
                    acc.withdraw(with);
                }
                System.out.println("Final balance: "+Account.getBal());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        // TODO Auto-generated method stub

        Person p1 = new Person("Person1");
        Person p2 = new Person("Person2");
        Person p3 = new Person("Person3");
        BankThread bt1 = new BankThread(p1);
        bt1.start();
        bt1.join();
        BankThread bt2 = new BankThread(p2);
        bt2.start();
        bt2.join();
        BankThread bt3 = new BankThread(p3);
        bt3.start();
        bt3.join();
    }

}

As I mentioned, it's an example I found and modified. This works but not correctly I think. In the threads class, the for loop goes and executes the code for each thread 3 times. And another problem I have is that the account balance remains the same for each thread. So, if I have 100 final balance for my first thread, the second one starts the same, with 100 balance and not from 0. If I have different objects, it should start from 0 right?

Here's a screenshot.

enter image description here

2

There are 2 best solutions below

1
On BEST ANSWER

Your described scenario mirrors the usage of static member fields in your Account class. The keyword static means that the fields are not object-bounded anymore, because they are class-bounded. So every instance of your Account object will have the same static field over any instance of it.

To fix it you have to remove the static fields

 public static int balance;
 public static Account acc;
 private static Person p;
0
On

First of all as it is mentioned in comments it is wrong name for Account class. Static field means this field is class dependent, not object (instance of class) dependent. So you will have those static field shared across application, which can be good example for multi threading.

For loop goes three times for each thread because it is meant to

for (int i = 0; i < 3; i++) {

it will be invoked for i=0, i=1 and i=2

If you want to play with multithreading with shared resources how it is in this example my advice to you is change the name of the Account class to FamilyAccount, and Person to FamilyMember, and think about this as shared account for family members. It will have more logic to have one account, and then you can play with multithreading and check if for example every member see actual amount of money.

If you will remove static field i think it will have no sense in case of multithreading. If every person have one Account, and they're working as one thread there is no need for synchronization.

Also your Account class is weird case of Singleton where there is public Constructor and getAcc method, which always return same instance of class.

I encourage you to look and read about transactions and Singleton for better understanding of case.