【问题标题】:Handling producer thread when no consumers are ready当没有消费者准备好时处理生产者线程
【发布时间】:2011-10-16 19:30:06
【问题描述】:

关于处理以下场景的模式建议:

将事件分派给消费者的单个线程。每个事件和消费者之间存在 1:1 的关系(每个事件根据事件/消费者 id 匹配分派给单个消费者)。

消费者以不同的速度处理事件,并且可以以可配置的批量大小来消费事件(例如,消费者一次可以消费 20 个事件)。

生产者线程应该始终能够将事件分派给能够消费的消费者。每个消费者维护一个它已经消费的事件队列(可能是批量)并在自己的线程上处理这些事件,因此从生产者到消费者的切换是异步的。

如果任何时候都没有消费者可以消费,调度线程应该怎么办?

  • yield()
  • wait() 并强制消费者拨打 notify() 就可以了
  • sleep() 固定时间段
  • 自旋

有任何理由偏爱其中一个吗?

一些优点和缺点:

  • 收益很简单
  • 强制消费者调用 notify 会增加复杂性
  • 固定时间的睡眠将适合对时间不敏感的要求
  • 自旋会占用 CPU,除非我们需要尽可能快的事件传递,否则这是不必要的

还有其他注意事项吗?

【问题讨论】:

  • 完全清楚:您说的是从调度程序直接移交给消费者,中间没有事件队列?
  • 抱歉,不清楚。从调度程序到消费者的切换是异步的,每个消费者都维护自己的事件队列。
  • 完整的句子有助于理解场景。此外,如果一个消费者可以消费多个事件,那不是“1:1”。
  • 消费者可以批量消费事件,并且只有一个消费者可以消费任何一个事件(调度线程根据ID为每个事件查找正确的消费者)
  • 事件是如何产生的?有没有等待下一个事件生成的方法?如果您需要做的就是在生产者线程上创建一个循环,该循环调用此方法并在生成事件时将每个事件分派给正确的消费者。这样可以确保消费者总是在事件到达后立即收到事件,并且由于生产者线程在其余时间等待,因此没有不必要的 CPU 负载。

标签: java multithreading concurrency producer-consumer


【解决方案1】:

您应该考虑的另一种方法是将其写入BlockingQueue。让队列管理在没有监听器的情况下发送的请求。

更好的是:编写一个拥有BlockingQueue 并维护ListConsumersBroker。当Producer 发送一个新的Event 时,让Broker 通知ConsumersList

我会使用自 JDK 1.0 起内置于 Java Beans 中的 PropertyChangeListenerEventObject 在内存中执行此操作。

【讨论】:

  • 如果我有一个生产者线程,我不希望它阻塞一个消费者,而其他人可能会消费
  • 生产者只会在BlockingQueue 已满时才会阻塞(即使那样,这也取决于您用于将元素插入队列的方法)。如果某些消费者将处理批量事件,则应使用 LinkedBlockingQueue 或 ArrayBlockingQueue(另一种选择是 SynchronousQueue,但这仅在您想一次仅发送一个事件并阻止生产者时才有用,除非有消费者准备好了,正在倾听)。
  • 已编辑问题以反映每个消费者都有自己的线程和已处理的事件队列这一事实。
【解决方案2】:

a) 您可以选择yield,但取决于环境的好坏,这基本上会变成无操作。所以这基本上与旋转具有相同的结果。

b) 睡眠是一个简单的选择,但你应该想出睡多长时间。执行sleep(0) 也无济于事,因为它与执行 (a) 相同

通知的力量更复杂,但您可以完全控制自己的流程。

【讨论】:

  • 你的意思是使用阻塞队列作为生产者和消费者之间的事件切换队列吗?如果有多个消费者(每个都在自己的线程上)和一个生产者线程,那么这不会导致生产者有时会阻塞等待消费者,而它可能会向另一个消费者分派不同的事件吗?
  • @Joel:我明白你的意思了。我认为如果你有时间你应该去通知
【解决方案3】:

看看JMS。 JMS 旨在处理这种用例。

在您的场景中,完整的 JMS 安装可能是多余的——您没有提供足够的信息。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-09-24
    • 2017-02-01
    • 2012-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多