This method is correct and should be used:
public synchronized double withDrawFromPrivateBalance(double a) { balance -= a; return balance; }
It correctly restricts access to the internal state of the account to only one thread at a time. However, your balance
field is public
(therefore not internal), which is the root cause of all your problems:
public double balance = 1500;
Using the public
modifier, you get access to it from two threads:
private synchronized void find(){ localBalance = myTargetAccount.balance; System.out.println(getName() + ": local balance = " + localBalance); localBalance -= 100; myTargetAccount.balance = localBalance; }
This method, although it looks correct with the synchronized
, is not. You create two threads, and a synchronized
thread is basically a lock bound to an object. This means that these two threads have separate locks, and each can access its own lock.
Think about your withDrawFromPrivateBalance()
method. If you have two instances of the Account
class, you can safely call this method from two threads on two different objects. However, you cannot call withDrawFromPrivateBalance()
on the same object from more than one thread due to the synchronized
. It looks like.
You can fix this in two ways: either use withDrawFromPrivateBalance()
directly (note that synchronized
no longer required here):
private void find(){ myTargetAccount.withDrawFromPrivateBalance(100); }
or lock the same object in both threads, unlike locking on two independent instances of the Thread
object:
private void find(){ synchronized(myTargetAccount) { localBalance = myTargetAccount.balance; System.out.println(getName() + ": local balance = " + localBalance); localBalance -= 100; myTargetAccount.balance = localBalance; } }
The last solution is obviously inferior to the first, because somewhere itβs easy to forget about external synchronization. Also, you should never use public fields.