我已经编写了一个Java类,并且有人检查了代码并坚持认为方法calculate
中可能存在争用条件。这是类代码的简化版本:
public class MyClass {
private List<Integer> list;
private final ReadWriteLock lock;
public MyClass() {
list = new ArrayList<>();
lock = new ReentrantReadWriteLock();
}
public void add(Integer integer) {
lock.writeLock().lock();
try {
list.add(integer);
} finally {
lock.writeLock().unlock();
}
}
public void deleteAll() {
lock.writeLock().lock();
try {
list.clear();
} finally {
lock.writeLock().unlock();
}
}
public Integer calculate() {
List<Integer> newList = new ArrayList<>();
Integer result = 0;
lock.readLock().lock();
try {
list.forEach(integer -> {
// calculation logic that reads values from 'list' and adds only a subset of elements from 'list' in 'newList'
});
} finally {
lock.readLock().unlock();
}
setList(newList);
return result;
}
private void setList(List<Integer> newList) {
lock.writeLock().lock();
try {
list = newList;
} finally {
lock.writeLock().unlock();
}
}
}
现在我的问题是:
此方法是否真的会出现竞争条件,如果可以,我该如何解决(使用锁或使用任何其他方法使类线程安全)?
任何建议将不胜感激。
答案 0 :(得分:4)
创建newList
与调用setList(newList)
之间存在时间间隔。我们可以假设这个时间间隔是任意长的,并且一切都会在它持续时发生,例如另一个线程添加了一个必须保留的对象,但是当调用setList(newList)
用该新对象删除list
时,它将丢失。
实际上,方法calculate
正在修改,应该在写锁定下完成所有工作。
答案 1 :(得分:1)
为澄清以上内容……声明
List<Integer> newList = new ArrayList<>();
...实例化一个数据结构(list
...),该结构随后将在打算由lock.readLock().lock();
保护但不包含在其中的代码块中使用。因此,它不受保护。
要解决此问题,newList
的声明中不应包含初始化。在受锁保护的块之外,不应存在任何会影响此变量的假定值的东西。