与独立消费者同时处理单个InputStream

时间:2012-07-04 20:12:02

标签: java concurrency stream inputstream

我需要生成N个消费者线程,它们同时处理相同的InputStream,例如 - 以某种方式转换它,计算校验和或数字签名等。这些消费者不依赖于彼此,并且所有消费者都使用第三方库,接受InputStream作为数据源。

所以我能做的是 - 创建一些InputStream的实现,它将

  • 从“父”流
  • 中读取数据块
  • 取消阻止消费者
  • 等到每个消费者阅读整个块
  • 阅读下一个块
虽然看起来很简单,但是当某些消费者死亡时,可能会出现各种问题,例如活锁,实现所有的InputStream方法,使用障碍/锁存器来控制消费者自己的叉/连接等。

一位好友告诉我,这是半个小时的实施,它是我的晚上。

我更喜欢使用足够成熟的东西(谷歌搜索没有带来结果,我的google-fu还不够好?)或者不打扰并将整个“源”流复制到临时文件中用它作为数据来源。后一种解决方案似乎更可靠,但最终可能会创建千兆字节文件(例如处理流式音频时)。

3 个答案:

答案 0 :(得分:3)

我看到它的方式,你应该至少有一些缓冲,这样不同的消费者可以以不同的速度穿过溪流而不会被当前最慢的消费者所困扰。这基本上可以确保最坏情况下的性能,并且并发性的好处很少。

比如,您可以使用目前已使用它的消费者标记每个块,然后删除那些完全用尽的块。也许这可以通过每个消费者持有对尚未使用的每个块的引用来实现,这将允许GC自动处理使用过的块。生产者可能会将WeakReference列表保存到块中,以便它可以处理尚未使用的块数,并以此为基础进行限制。

我也在考虑为每个线程提供一个单独的InputStream实例,该实例在内部与生产者InputStream进行通信。通过这种方式,您可以轻松解决您的活锁危险:try ... finally { is.close(); } - 垂死的消费者关闭自己的输入流。这是传达给制作人的。

我对每个消费者使用ArrayBlockingQueue有一些想法。确保所有消费者都得到适当的喂养,而不会让生产者阻止或忙碌等待会有一些困难。

答案 1 :(得分:0)

您是否考虑过使用管道流?您的生产者可以有一个或多个PipedOuputStream,它会抛出从文件中读取的任何内容。在管道的另一端,您有不同的消费者线程读取相应的PipedInputstream(这是一个可以与您的库共享的InputStream)。

您的生产者线程可以决定通过哪种管道数据发送,通过这种方式,为管道另一侧的给定消费者线程读取提供数据。

如果您需要从消费者线程中获取数据,那么您可以在相反的方向创建另一个管道,以便将数据发回给您。

答案 2 :(得分:0)

您可以尝试一些Java Messaging Service(JMS)实现,如Apache ActiveMQ

在您的情况下,您需要创建一个所谓的主题(请参阅Topics vs. Queues)。一个主题由生产者创建,并发布给N个消费者,这些消费者可以同时运行,每个消费者都接收完全相同的数据。

由于您想使用InputStream,因此有一章介绍如何send messages are streams

我认为,通常,生产者和消费者将是独立的进程,可能在网络上的不同机器上运行。我认为您可以将其配置为在单个JVM中完全运行。这取决于JMS的实现。这些也很有名:HornetQ by JBossRabbitMQ和其他一大堆。