【问题标题】:Is this code threadsafe, using Java 8 Lambdas - stream.forEach此代码是否线程安全,使用 Java 8 Lambda - stream.forEach
【发布时间】:2019-08-13 22:04:42
【问题描述】:

假设我有一个书籍元素列表:List<Book> libraryBooks 和以下代码:

List<BookAuthor> authors = new ArrayList<>();
libraryBooks.stream().forEach(e -> {
                                     authors.add(createAuthor(e));
                                   });

我环顾四周,发现了类似的问题,(如here)但我还不相信。因为我一直在阅读有关该主题的书,并且该书似乎表明,如果流并行运行,上述内容可能会引入竞争条件-但我没有使用并行流,因此上述内容也会受到竞争条件的影响?还是这本书有误/误导?

这是我所指的书中的摘录:

【问题讨论】:

  • “如果流并行运行,上述可能会引入竞争条件” - 它不一定是并行流,因为它不是线程安全的。当您在 forEach 中添加元素时,任何其他线程都可能尝试修改 authors。
  • 我相信您的书展示了正确、惯用的方式来做您想做的事。为什么不使用这种惯用方式?
  • 我发布的上述示例实际上是一个非常简单的示例,但我正在查看现有应用程序中的一些代码,它实际上做了更复杂的事情(即,使用构建器创建对象)然后将该新对象添加到列表中,但与我发布的上述示例相同。我只是想知道这是否会导致比赛条件?
  • @Nena 使用流的良好做法是编写可并行化的代码。一般来说,一个人应该能够用parallelStream() 替换stream() 并且仍然有正确的代码。那里的情况并非如此,因为 ArrayList 不是线程安全的,并且会从并发线程进行修改。这就是本书所说的:你应该编写parallel-ready代码。如果它是顺序的,则它没有任何竞争条件,因为没有竞争。但它不是并行就绪的,因为如果它是并行的,它将有一个竞争条件。

标签: java lambda foreach race-condition


【解决方案1】:

当您需要通过对每个元素应用函数来创建新的项目列表时,map 是您应该使用的函数。你应该这样写:

List<BookAuthor> authors = libraryBooks.stream()
            .map(e -> createAuthor(e))
            .collect(Collectors.toList());

【讨论】:

  • 您能解释一下这以何种方式回答了 OP 的问题吗?我知道这是用一般流构建List 的正确方法,但它如何回答线程安全问题?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-29
  • 1970-01-01
相关资源
最近更新 更多