I want to make a simple bank using thread in Java. But I can't make deposit(), withdraw() to synchronize. There is not synchronized balance all the time. I write 'synchronized' keyword in the method name, but it never works. Also, I make 'synchronizedList' in my ArrayList (I should use array list to make this) but it never works. How can I get an appropriate balance? please help me.
import java.security.SecureRandom;
public class Transaction implements Runnable {
private static final SecureRandom generator = new SecureRandom();
private final int sleepTime; // random sleep time for thread
private String transaction;
private int amount;
private static int balance;
private Account account = new Account();
public Transaction (String transaction, int amount) {
this.transaction = transaction;
this.amount = amount;
sleepTime = generator.nextInt(2000);
}
@Override
public void run() {
// TODO Auto-generated method stub
try {
if(transaction == "deposit") {
balance = account.deposit(amount);
} else if (transaction == "withdraw") {
balance = account.withdraw(amount);
}
System.out.println("[" + transaction + "] amount : " + amount +" balance : " + balance);
Thread.sleep(sleepTime);
}catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt(); // re-interrupt the thread
}
}
}
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class AccountTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
// create ArrayList
List<Transaction> john = Collections.synchronizedList(new ArrayList<>());
// add Transaction objects
john.add(new Transaction("deposit", 1000));
john.add(new Transaction("withdraw", 500));
john.add(new Transaction("withdraw", 200));
john.add(new Transaction("deposit", 3000));
// execute Thread Pool
ExecutorService executorService = Executors.newCachedThreadPool();
// start transactions
for(int i=0; i<john.size(); i++) {
executorService.execute(john.get(i));
}
// shut down Thread Pool
}
}
public class Account {
// deposit withdraw
private static int balance;
public synchronized int deposit(int amount) {
balance += amount;
return balance;
}
public synchronized int withdraw(int amount) {
balance -= amount;
return balance;
}
}
The core mistake here is that each Transaction has its own Account. Each thread is acquiring the lock on its own instance of Account, with the result that there is no actual locking going on.
You need a lock that is shared between the threads, they need to be trying to modify the same Account object. Instance methods marked with synchronized
acquire a lock baked into the object instance.
Making the balance on Account static is a dirty hack that makes all the balance data end up in the same place (which works only as long as you have only one Account) but doesn't address the synchronization problem.
(You could change the Account methods to be static too, and that would fix the synchronization issue since all the threads would be acquiring the lock on the class, and there is only one class. But of course it stops working once you need a second account so it is not a great solution.)
Rework this so that, instead of having each Transaction create its own account, you share the same Account object across Transactions. You can pass the Account into the Transaction as a constructor argument.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.