If i have an account in a local commercial bank, I can choose to have two seperate accounts under the same name. 1. A Savings account and 2. A checking account. The fee on checking account is 10% of the balance, while the interest on the savings is 10%. I deposit a $1000 on the checking account and another $1000 on my savings account. Just to balance things out, I choose a scheduled transfer of $100 from savings --> checking. This basically because 10% interest on the savings will cover the fee.

To my suprise, my accounts fall short of expected $2000. The bank claims their banking software is perfectly alright. After entering the values I provided, the final combined value was $2000. THe banking software had three threads, i. withdraws the fee from the checking account, ii. adds interest to the savings account and iii. transfers $100 from the savings to the checking account.

Below is the code:

Account.Java
Code:
package banking;

public class Account {
    final String accountHolder;
    final String accountType;
    double balance=0;
    
    public Account(String name, String type,double credit) {
        this.accountHolder = name;
        this.accountType = type;        
        this.balance=credit;
    }
    
    public void deposit(double credit) {
        balance += credit;
    }
    
    public void withdraw(double credit) {
        balance -= credit;
    }
    
    public void addinterest(double rate) {
        balance *= (100+rate)/100.0;
    }
    
}
Banking.java
Code:
package banking;

public class Banking {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws InterruptedException {
        System.out.println("Application started");
        
        Account savings  = new Account("kchad","Super Saver",1000);
        Account checking = new Account("kchad","Free Checking",1000);
        
        System.out.println("\nBeginning of month");
        System.out.println(savings.accountType + ":\t"+ savings.balance);
        System.out.println(checking.accountType + ":\t"+ checking.balance);
        System.out.println("Total before \t"+ (checking.balance+savings.balance));
        
        
        Interest checkInterest = new Interest(checking, -10);        
        Interest saveInterest = new Interest(savings, 10);   
        Transfer transfer = new Transfer(savings,checking,100);  
              
              
        checkInterest.start();
        saveInterest.start(); 
        transfer.start();
              
              
        Thread.sleep(520);
        System.out.println("\nEnd of month");
        System.out.println(savings.accountType + ":\t"+ savings.balance);
        System.out.println(checking.accountType + ":\t"+ checking.balance);
        System.out.println("Total  after \t"+ (checking.balance+savings.balance));
        System.out.println("Main thread finished");
    }
}
Interest.java
Code:
package banking;

import java.util.logging.Level;
import java.util.logging.Logger;


class Interest extends java.lang.Thread {
    final Account myAccount;
    double myRate;
    
    public Interest(Account account, double rate) {
          this.myAccount=account;
          this.myRate = rate;
          setName("Interest");
    }
   
    @Override
    public void run() {
        
         System.out.println("Interest this month on "+  myAccount.accountType + ":\t" + myAccount.balance*myRate/100.0);
         myAccount.addinterest(myRate);
         
          //System.out.println(getName() + " to account " + myAccount.accountType + " successfully applied");
    }
    
    
    
}
Transfer.java
Code:
package banking;

import java.util.logging.Level;
import java.util.logging.Logger;

class Transfer extends java.lang.Thread {    
    final Account myAccount1;
    Account myAccount2;
    double myAmount;
    
    public Transfer(Account account1,Account account2, double amount) {
          this.myAccount1=account1;
          this.myAccount2=account2;
          this.myAmount = amount;
          setName("Transfer");
    }
   
    @Override
    public void run() {
        
        
        myAccount1.withdraw(myAmount);
        myAccount2.deposit(myAmount);
       
        System.out.println(getName() + " from " + myAccount1.accountType + " to " + myAccount2.accountType + " successfully applied");
    }
    
    
    
}
How can i reproduce the problem stated. and how synchronization to solve the banking problem