【问题标题】:Scala: thread-safe circular iteratorScala:线程安全的循环迭代器
【发布时间】:2018-03-04 12:56:56
【问题描述】:

在 scala 中创建线程安全的无限循环迭代器的正确方法是什么?似乎以下不是线程安全的(从迭代器上的多个线程同时迭代偶尔会抛出异常):

val map = Map(1->"one", 2->"two")
val iterator = Iterator.continually(map).flatten

您将如何更正此问题以使其成为线程安全的?

【问题讨论】:

  • 迭代器不能真正成为线程安全的,因为 (1) 它是固有可变的,并且 (2) 使用运算符涉及调用两种不同的方法:hasNextnext。同步这些方法不会有多大效果,因为在一个线程调用hasNext 并确定它返回true 之后,另一个线程可能会调用next,消耗当前值,这可能是最后一个值。所以第一个线程将调用next 并抛出异常,因为迭代器是空的。迭代器绝对不是在多个线程之间共享的正确抽象。
  • 那么你有什么建议?我需要每个访问集合的线程来获取下一个有效值。我还有哪些其他选择?
  • 如果没有关于您的特定用例的太多信息,我会说可能使用类似 java.util.concurrent.ConcurrentLinkedQueue 的例子。
  • 我没有看到任何方法可以使其循环运行?
  • 您可以在 synchronized way 中使用来自 ApacheCommons 的 CircularFifoBuffer

标签: scala


【解决方案1】:

我遇到了同样的问题,但我认为我们可以这样做是安全的,因为正如 here 所讨论的那样独立于实现。

iterator.synchronized(
  iterator.next()
)

【讨论】:

  • 这种方法的问题在于,不仅 hasNext 仍然不是可重入的,而且它与 next 也不是原子的,即 hasNext 可以返回 true,但是其他一些线程可能会在当前线程可以使用之前消耗最后一个元素元素(此时它会得到一个空值,然后很可能是一个 NPE)。
【解决方案2】:

只需包装到提供者。像这样:

class Iterator2ProviderAdapter[A](iterator: Iterator[A]) {
    def get: A = synchronized(iterator.next())
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-02-08
    • 2019-08-20
    • 2017-04-15
    • 2014-12-12
    • 1970-01-01
    • 1970-01-01
    • 2018-04-07
    • 2014-03-18
    相关资源
    最近更新 更多