【发布时间】:2016-12-05 16:12:28
【问题描述】:
Javadoc 和一些答案 (Threads - Why a Lock has to be followed by try and finally) 指出:
在大多数情况下,应使用以下成语:
Lock l = ...;
l.lock();
try {
// access the resource protected by this lock
} finally {
l.unlock();
}
我在标准 Java 库中看到了这种习惯用法的示例。 这是我使用它的例子。字段 acc1 和 acc2 代表银行帐户的一个众所周知的示例。主要约束是 acc 的值的总和 - 它应该是 0。
public class Main {
int acc1;
int acc2;
ReadWriteLock lock = new ReentrantReadWriteLock();
public int readSum() {
lock.readLock().lock();
try {
return acc1 + acc2;
} finally {
lock.readLock().unlock();
}
}
public void transfer() {
lock.writeLock().lock();
try {
acc1--; // constraint is corrupted
// exception throwed here
acc2++; // constraint is regained
} finally {
lock.writeLock().unlock();
}
}
}
我理解在读取情况下使用成语:如果在读取方法中抛出异常,其他线程仍然可以读取/写入一致的资源。但是如果在写方法中抛出异常,读方法可以读取不一致的资源。
为什么读取不一致的值比无限锁等待更可取? 为什么 Java 库的作者更喜欢这种行为?
【问题讨论】:
-
锁提供了某些形式的事务行为(例如一致的数据视图)。但是,它们不提供回滚功能。你要么需要自己实现,要么使用数据库。
-
当您的软件运行一个每天处理价值数百万美元业务的商业网站时,如果它对 I/O 错误做出反应而永远挂起,您的客户将不会高兴。 (别问我怎么知道的!)
-
PS:@GhostCat 的回答谈到了罗伯特(“鲍勃叔叔”)马丁所说的关注点分离——这个想法是,如果你让一团代码负责为了解决两个或多个不同的问题(例如,锁定和错误处理),当需求发生变化时,它将变成未来维护的噩梦。查看鲍勃叔叔的书:amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/…
-
@james large IOException 已检查,这对您来说并不奇怪。你应该抓住它,回滚资源状态,然后调用解锁。但是如果在 ConcurrentHashMap.put 方法中抛出 OutOfMemoryError ,它只会解锁 map 并允许其他线程使用损坏的 hashMap。
-
当我收到 OOME 时,我希望服务被拒绝,但不是数据损坏。
标签: java multithreading locking try-finally