使用Java锁的竞争条件的可能性

时间:2019-06-04 02:15:50

标签: java multithreading concurrency java-8 thread-safety

我已经编写了一个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();
        }
    }
}

现在我的问题是:

此方法是否真的会出现竞争条件,如果可以,我该如何解决(使用锁或使用任何其他方法使类线程安全)?

任何建议将不胜感激。

2 个答案:

答案 0 :(得分:4)

创建newList与调用setList(newList)之间存在时间间隔。我们可以假设这个时间间隔是任意长的,并且一切都会在它持续时发生,例如另一个线程添加了一个必须保留的对象,但是当调用setList(newList)用该新对象删除list时,它将丢失。

实际上,方法calculate正在修改,应该在写锁定下完成所有工作。

答案 1 :(得分:1)

为澄清以上内容……声明

List<Integer> newList = new ArrayList<>();

...实例化一个数据结构(list ...),该结构随后将在打算由lock.readLock().lock();保护但不包含在其中的代码块中使用。因此,它不受保护。

要解决此问题,newList的声明中不应包含初始化。在受锁保护的块之外,不应存在任何会影响此变量的假定值的东西。