【问题标题】:Can a forEach lambda result in a race condition?forEach lambda 会导致竞争条件吗?
【发布时间】:2018-04-26 09:48:28
【问题描述】:

我不确定 lambda 在实践中是如何工作的,而且我很担心,因为在某些情况下,如果你不正确地使用 lambda,它们可能会导致诸如 ConcurrentModificationExceptions 之类的错误,这似乎表明存在竞争条件。
考虑下面的代码。

private class deltaCalculator{
    Double valueA;
    Double valueB;

    //Init delta
    volatile Double valueDelta = null;

    private void calculateMinimum(List<T> dataSource){
        dataSource.forEach((entry -> {
            valueA = entry.getA();
            valueB = entry.getB();
            Double dummyDelta;

            dummyDelta = Math.abs(valueA - valueB);

            if(valueDelta == null){
                setDelta(dummyDelta);
            }else {
                setDelta((valueDelta > dummyDelta) ? dummyDelta : valueDelta);
            }
        }));
    }

    private void setDelta(Double d){
        this.valueDelta = d;
    }
}

forEach 循环如何运作?不同的调用是否会传递到 JVM 认为合适的不同线程,从而导致出现可能导致不正确的最小值计算的竞争条件的可能性?
如果不是,为什么 forEach lambda 会抛出 ConcurrentModificationException?

【问题讨论】:

  • 我看不出是什么导致了 ConcurrentModificationException ,你确定没有其他地方可以修改同一个 List&lt;T&gt; dataSource 对象吗?
  • 我并不是说在这种情况下您可以获得 CME,但是如果您尝试在 forEach 中从集合中删除元素等操作,则会抛出 CME。
  • 啊,好的。然后 +1 到 berry120 回答。这里不涉及多线程,只要您不使用 list.parallelStream().forEach 之类的东西,就会同步调用 lambda - 但可能会产生误导的是,我们通常(有时错误地)将“并发”一词与多线程相关联。

标签: java lambda thread-safety


【解决方案1】:

如果您在 for each 循环运行时尝试修改正在迭代的集合,您将收到 ConcurrentModificationException。这可以完全在一个单独的线程中完成,但更常见的是在您尝试修改循环体中的集合时发生。

不同的调用是否会被传递到 JVM 认为合适的不同线程,从而引发可能导致不正确的最小值计算的竞争条件?

没有。上面的示例中没有发生多线程。

【讨论】:

  • 如果发生多线程,这意味着函数是不安全的,我们不能保证它总能找到最小的差异,对吗?
  • 如果发生 unsafe 多线程,影响了单独线程中的上述相关字段,那么您不能保证它总是正确的。这不是特定于 lambdas 或每个循环的,对于在任何对象上执行的任何方法都是如此。但是,这永远不会“在后台”发生——它只会是您编写的特定、不安全的多线程代码的结果。 (JVM 从来不会以这种方式进行不安全的多线程优化,如果这样做将是一场噩梦。)
猜你喜欢
  • 2021-09-03
  • 2014-02-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多