为了提高我对并发问题的理解,我正在研究以下场景(编辑:我已将示例从列表更改为运行时,这更接近我正在尝试的) :
public class Example {
private final Object lock = new Object();
private final Runtime runtime = Runtime.getRuntime();
public void add(Object o) {
synchronized (lock) { runtime.exec(program + " -add "+o); }
}
public Object[] getAll() {
synchronized (lock) { return runtime.exec(program + " -list "); }
}
public void remove(Object o) {
synchronized (lock) { runtime.exec(program + " -remove "+o); }
}
}
就目前而言,每个方法在独立使用时都是线程安全的。现在,我想弄清楚的是如何处理调用类希望调用的位置:
for (Object o : example.getAll()) {
// problems if multiple threads perform this operation concurrently
example.remove(b);
}
但如前所述,无法保证调用 getAll() 和调用 remove() 之间的状态一致。如果多个线程调用它,我就会遇到麻烦。所以我的问题是 - 我应该如何让开发人员以线程安全的方式执行操作?理想情况下,我希望以一种让开发人员难以避免/错过的方式强制执行线程安全,但同时实现起来并不复杂。到目前为止,我可以想到三个选项:
A: 将锁设置为“this”,这样调用代码就可以访问同步对象,然后调用代码可以包装代码块。缺点:难以在编译时执行:
synchronized (example) {
for (Object o : example.getAll()) {
example.remove(b);
}
}
B:将合并后的代码放入 Example 类中 - 并从能够优化实现中获益,就像在本例中一样。缺点:添加扩展的痛苦,以及可能混合不相关的逻辑:
public class Example {
...
public void removeAll() {
synchronized (lock) { Runtime.exec(program + " -clear"); }
}
}
C:提供一个闭包类。缺点:过多的代码,可能过于慷慨的同步块(synchronized block),实际上可能使死锁更容易:
public interface ExampleClosure {
public void execute(Example example);
}
public Class Example {
...
public void execute(ExampleClosure closure) {
synchronized (this) { closure.execute(this); }
}
}
example.execute(new ExampleClosure() {
public void execute(Example example) {
for (Object o : example.getAll()) {
example.remove(b);
}
}
}
);
有什么我想念的吗?应该如何限定同步范围以确保代码是线程安全的?
最佳答案
使用通过 API 公开的 ReentrantReadWriteLock
。这样,如果有人需要同步多个 API 调用,他们可以在方法调用之外获取锁。
关于java - 确定同步范围?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3831315/