[英]How to synchronize threads in Java?
考慮下面的代碼。
public class Account {
private static List<Double> log = new ArrayList<Double>();
private double balance;
public Account(){balance = 0.0;}
public synchronized void deposit(double val){
balance = balance + val;
log.add(val);
}
public synchronized void withdraw(double val){
balance = balance - val;
log.add(val);
}
}
同步是否正確?
我會說是的,因為訪問變量日志的方法是原子的(多虧了同步這個詞)。 我是這樣測試的:
Account a = new Account();
Thread t = new Thread(()->a.deposit(30));
Thread j = new Thread(()->a.withdraw(20));
t.start();
j.start();
sleep(300);
System.out.println(Account.getLog());
在我看來,阻塞很好,只要一個線程正在使用日志變量,另一個線程就不會使用它。
但是,文本顯示了此解決方案(未解釋原因)(-> 代表替換):
log.add(val)->
synchronized(log)
{
log.add(val)
}
log.add(-val)->
synchronized(log)
{
log.add(-val)
}
class Account {
private static List<Double> log = new ArrayList<Double>();
private double balance;
public Account() {
balance = 0.0;
}
public synchronized void deposit(double val) {
balance = balance + val;
synchronized (log) {
log.add(val)
}
}
public synchronized void withdraw(double val) {
balance = balance - val;
synchronized (log) {
log.add(-val);
}
}
}
為什么要鎖定變量日志? 同步方法還不夠嗎?
解決方案代碼對我來說看起來是線程安全的:
balance
變量在持有賬戶互斥鎖的同時更新。log
在持有列表互斥鎖的同時更新。 一個小問題是log
應該是final
。 如果有任何事情能夠(例如意外地)為log
分配一個新值,則不能保證不同的線程看到/更新相同的列表 object。
但是,您的代碼版本不是線程安全的。 它在更新日志時不鎖定log
。 這意味着更新不同Account
對象的兩個線程可以同時嘗試更新log
列表。 那可能會破壞它。
(兩種)解決方案還有其他各種問題。 最關鍵的是您使用double
來表示貨幣值。 這違反了正常的會計慣例。 (如果你“偷”了一些銀行客戶的一些便士,一些銀行客戶會感到不安......由於浮點舍入錯誤。)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.