繁体   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