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