【问题标题】:How do you call this kind of concurrency related class? And is there a standard implementation?这种并发相关的类怎么称呼?是否有标准实施?
【发布时间】:2011-02-14 07:29:15
【问题描述】:

由于我找不到它的标准实现,我创建了这个小类,但我认为这样简单的东西应该已经存在于某个地方:

class ReturnValue {
    private var value = false

    private val latch = new java.util.concurrent.CountDownLatch(1)

    def setValue(aValue: Boolean) {
        value = aValue
        latch.countDown()
    }
    def getValue() = {
        latch.await
        value
    }
}

它的目的是在两个线程之间交换一个值(在我的例子中是主线程 + EDT)。从使用 getValue() 方法的代码来看,它看起来几乎像一个 Future,但我发现的 Future 实现期望调用者提供要执行的代码,这在我的情况下不起作用。

所以我的问题是:

  • 这样的东西有名字吗?
  • 在 java 或 scala 中是否有标准实现?
  • 我的实现是否正确?

【问题讨论】:

  • 我称之为“不是 Java” :-)
  • 两个问题... setValue 应该被多次调用吗?如果 setValue 应该被多次调用,那么这段代码真的正确同步了吗? (我对 Scala 了解不多,但我看不到如何保证 getValue 会返回正确的值。我 latch.await 够了吗?)
  • @Gugussee 正确:setValue 只会调用一次。 latch.await 足够了吗?我想是的,但我不会赌钱。
  • @Gugussee 我碰巧又看了一遍……我同意你的看法。设置/和访问值应该是同步的,但是对锁存器的访问应该在同步块之外......我认为。

标签: java scala concurrency


【解决方案1】:

Scala 标准库以scala.concurrent.SyncVar[T] 类的形式提供了这种同步机制。

这个 Scala REPL 会话演示了它是如何工作的:

scala> import concurrent._           
import concurrent._

scala> import ops._                  
import ops._

我正在导入 ops._ 以轻松生成另一个 Thread

scala> val syncInt = new SyncVar[Int]
syncInt: scala.concurrent.SyncVar[Int] = scala.concurrent.SyncVar@17823918

scala> spawn { println("got %d" format syncInt.get) }

我正在生成另一个线程。 get 阻塞,直到 syncInt 中有值。

scala> syncInt.isSet
res1: Boolean = false

scala> syncInt.set(103)

scala> got 103

以上是我们之前创建的线程打印出来的。

scala> syncInt.isSet
res3: Boolean = true

scala> syncInt.get
res4: Int = 103

【讨论】:

    【解决方案2】:

    看起来有点类似于带有一个元素的synchronous queue,其中消费者必须wait 才能让生产者提供价值。

    【讨论】:

    • 虽然在SynchronousQueue生产者也等待消费者取值。
    • SynchronousQueue 没有元素。来自 javadocs:“同步队列没有任何内部容量,甚至没有容量。”
    【解决方案3】:

    在我看来,这有点像Exchanger,只是它更单方面……你看过了吗?基本上你不需要担心你从“等待”方面提供了什么,或者你从“提供”部分收到了什么。

    我同意你的观点,除了“可执行”部分之外,它看起来像是一个未来。

    【讨论】:

    • 是的,我记得我看着那个并想'我只需要它的一半'
    • +1 用于建议 Exchanger,但关键区别在于“setter”线程也必须阻塞,直到“getter”线程称为getValue()。在一般情况下,我怀疑这是不可取的(否则您可以让 getter 提供一个被 setter 线程忽略的虚拟值)。
    【解决方案4】:

    我创建了一个非常相似的东西,称为BlockingReference,我需要消费者(一个或多个)能够读取最新的值或阻止,直到有一个可用。本质上,它就像一个单元素队列,因为生产者线程可以随时发布一个新值,然后继续执行。在需要发布的唯一信息是某种状态更新的情况下,这是相关的。我在多线程内容分发缓存中使用它来标记进度(其中一个线程下载内容,并且有多个消费者重新广播下载的字节)。与您的主要区别在于您的是一次性使用。

    此实现明显优于SynchronousQueueExchanger,因为它们都会阻塞生产者线程,直到发生切换。它在性能上优于 Scala SyncVar,因为生产者线程在没有任何阻塞的情况下实现,并且在功能上因为它可以支持多个消费者。它已经过大量性能优化。

    Atlassian Concurrency 库已获得 Apache2 许可,位于我们的公共 Maven 存储库中。

    【讨论】:

      【解决方案5】:

      这和flow programming有些关系。

      【讨论】:

        猜你喜欢
        • 2021-11-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-12-19
        • 2013-04-01
        • 1970-01-01
        • 1970-01-01
        • 2022-08-18
        相关资源
        最近更新 更多