簡體   English   中英

如何同步Java中的線程?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM