i'm exercising Java multithreading on an example of simple banking funcions. The programm is able to perform multiple transactions at once on different threads.
All accounts transfer money to the following account, the last transferes money to the first.
I want some feedback so I can improve my coding standards and practices, specifically on multithreading.
Banking class:
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
public class BankSystem
{
public static void main(String[] args)
{
List<Account> accounts = new ArrayList<>();
for (int i = 0; i < 5; i++)
{
accounts.add(new Account("user " + i, i, 100));
}
for (int i = 0; i < 5; i++)
{
if (i != 4)
{
accounts.get(i).setTransTarget(accounts.get(i + 1));
} else
{
accounts.get(i).setTransTarget(accounts.get(0));
}
accounts.get(i).start();
}
try
{
for (int i = 0; i < 5; i++)
{
accounts.get(i).join();
}
} catch (InterruptedException e)
{
e.printStackTrace();
}
accounts.forEach(n -> System.out.println(n.getBalance()));
}
public static void transactMoney(Account sender, Account receiver, float amountToTransfer)
{
Account firstLock = sender;
Account secondLock = receiver;
if (sender.accountNumber < receiver.accountNumber)
{
firstLock = receiver;
secondLock = sender;
}
System.out.println(Thread.currentThread().getName() + " waiting for first lock on user " + firstLock.accountNumber);
synchronized (firstLock)
{
System.out.println(Thread.currentThread().getName() + " got first lock on user " + firstLock.accountNumber);
System.out.println(Thread.currentThread().getName() + " waiting for second lock on user " + secondLock.accountNumber);
synchronized (secondLock)
{
System.out.println(Thread.currentThread().getName() + " got second lock on user " + secondLock.accountNumber);
sender.subtractBalance(amountToTransfer);
int delayTime = ThreadLocalRandom.current().nextInt(100, 600);
try
{
Thread.sleep(delayTime);
} catch (InterruptedException e)
{
e.printStackTrace();
}
receiver.addBalance(amountToTransfer);
System.out.println("\t" + Thread.currentThread().getName() + " withdraw $" + amountToTransfer);
}
System.out.println("\t" + Thread.currentThread().getName() + " released lock on user " + firstLock.accountNumber + " and " + secondLock.accountNumber);
}
}
}
Account class:
public class Account extends Thread
{
volatile float balance;
Account target;
int accountNumber;
public Account(String name, int accountNumber, int balance)
{
super(name);
this.accountNumber = accountNumber;
this.balance = balance;
}
@Override
public void run()
{
for (int i = 0; i < 2; i++)
{
BankSystem.transactMoney(this, target, 100);
}
}
public void setTransTarget(Account target)
{
this.target = target;
}
private void setBalance(float balance)
{
this.balance = balance;
}
public float getBalance()
{
return balance;
}
public void addBalance(float balance)
{
setBalance(getBalance() + balance);
}
public void subtractBalance(float balance)
{
setBalance(getBalance() - balance);
}
}
Output of Console:
user 4 waiting for first lock on user 4
user 0 waiting for first lock on user 1
user 1 waiting for first lock on user 2
user 2 waiting for first lock on user 3
user 3 waiting for first lock on user 4
user 1 got first lock on user 2
user 2 got first lock on user 3
user 0 got first lock on user 1
user 4 got first lock on user 4
user 1 waiting for second lock on user 1
user 2 waiting for second lock on user 2
user 0 waiting for second lock on user 0
user 4 waiting for second lock on user 0
user 0 got second lock on user 0
user 0 withdraw $100.0
user 4 got second lock on user 0
user 0 released lock on user 1 and 0
user 0 waiting for first lock on user 1
user 1 got second lock on user 1
user 4 withdraw $100.0
user 4 released lock on user 4 and 0
user 4 waiting for first lock on user 4
user 3 got first lock on user 4
user 3 waiting for second lock on user 3
user 1 withdraw $100.0
user 1 released lock on user 2 and 1
user 0 got first lock on user 1
user 1 waiting for first lock on user 2
user 2 got second lock on user 2
user 0 waiting for second lock on user 0
user 0 got second lock on user 0
user 0 withdraw $100.0
user 0 released lock on user 1 and 0
user 2 withdraw $100.0
user 2 released lock on user 3 and 2
user 1 got first lock on user 2
user 2 waiting for first lock on user 3
user 3 got second lock on user 3
user 1 waiting for second lock on user 1
user 1 got second lock on user 1
user 1 withdraw $100.0
user 1 released lock on user 2 and 1
user 3 withdraw $100.0
user 3 released lock on user 4 and 3
user 3 waiting for first lock on user 4
user 2 got first lock on user 3
user 4 got first lock on user 4
user 2 waiting for second lock on user 2
user 4 waiting for second lock on user 0
user 2 got second lock on user 2
user 4 got second lock on user 0
user 2 withdraw $100.0
user 2 released lock on user 3 and 2
user 4 withdraw $100.0
user 4 released lock on user 4 and 0
user 3 got first lock on user 4
user 3 waiting for second lock on user 3
user 3 got second lock on user 3
user 3 withdraw $100.0
user 3 released lock on user 4 and 3
user 0 balance 100.0
user 1 balance 100.0
user 2 balance 100.0
user 3 balance 100.0
user 4 balance 100.0