2013-07-05 45 views
4

如果队列已满,ArrayBlockingQueue将阻塞生产者线程,并且如果队列为空,它将阻塞使用者线程。阻塞队列是否失败了多线程的目的

这种阻塞的概念是否违背了多线程的思想?如果我有一个“主”线程,并让我们说我想将所有“日志记录”活动委托给另一个线程。所以基本上在我的主线程中,我创建了一个Runnable来记录输出,并将Runnable放在ArrayBlockingQueue上。这样做的全部目的是让'主'线程立即返回,而不会在昂贵的日志记录操作中浪费任何时间。

但是,如果队列已满,则主线程将被阻塞,并将等待一个点可用。那它对我们有什么帮助?

+6

线程争用,线程匮乏和不安全的并发访问都是多线程时必须解决的所有问题。线程对共享资源不会很好,除非明确告诉。 – Makoto

+0

你只考虑队列已满的情况。在其他情况下,线程不会阻塞。 –

+1

@Makoto你在做什么?这与这个问题无关。顺便说一句,BlockingQueues的线程安全...请参阅http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/BlockingQueue.html –

回答

5

我认为这是设计师的决定。如果他选择阻塞模式,则ArrayBlockingQueue为其提供put方法。如果设计者不想阻塞模式ArrayBlockingQueue有offer方法,当队列满时会返回false,但是他需要决定如何处理regected logging事件。

0

这听起来像你有一个普遍的想法,为什么你会使用像ArrayBlockingQueue之类的线程之间进行交谈。

拥有一个阻塞队列使您可以选择在事件出现问题时选择不同的方式处理后台工作线程,而不是盲目向队列添加更多请求。如果队列中有空间,则没有阻塞。

为了您的具体使用情况,不过,我会用ExecutorService而不是读/直接写入队列,它创建的后台工作线程池:

http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ExecutorService.html

pool = Executors.newFixedThreadPool(poolSize); 
pool.submit(myRunnable); 
+0

使用具有多个线程的执行程序不会gaurentee在处理队列项目时进行排序。这不是问题的要求,但值得一提的是。 –

+1

正确 - 虽然如果只有一个线程(poolSize = 1),它是等效的。 – wrschneider

+0

好点。从可运行的结果中获取结果会非常好,可以将它排队到某个优先事件处理管理器中,然后在下一个项目完成时通知监听器。这样你也可以利用多个内核。再次,这假定排序很重要。而且,这种额外的同步和排序不会减慢使用单线程的速度。 –

2

阻塞是一种必要的功能的多线程。您必须阻止同步访问数据。它并没有打破多线程的目的。

我会建议抛出一个异常,当生产者试图提交一个项目的队列已满。有些方法可以事先测试容量是否足够,我相信。

这将允许调用代码决定如何处理完整队列。

如果从队列处理项目时的执行顺序不重要,我建议使用一个线程池(在Java中称为ExecutorService)。

0

您必须选择排队已满时该怎么做。在排队阻塞的情况下,该选择是等待。

另一种选择是在队列已满时丢弃新的对象;你可以通过offer来实现。

你必须作出权衡。

+1

如果您愿意,“BlockingQueue”类已经完成“完全扔掉”。只需使用'.offer()'。 –

+0

@BrunoReis谢谢,我瞥了一眼API并错过了它! –

7

该队列不会阻止异常,它阻止向系统中引入额外的质量。在这种情况下,它是预防饥饿

查看一组线程,其中一个线程非常快速地生成工作单元。如果队列允许无限增长,那么“快速生产者”队列可能会占用所有生产能力。有时候,预防这种副作用比让所有线程畅通都更重要。

2

在你的例子中,我会考虑阻塞是一个功能:它可以防止OutOfMemoryError。

一般来说,你的一个线程速度不够快,无法应付分配的负载。所以其他人必须以某种方式放慢速度,以免危及整个应用程序。

另一方面,如果负载是平衡的,队列不会阻塞。

0

多线程程序是不确定的,只要你不能事先说:N正好只要生产者的行为将采取为m的消费行为。因此,n生产者和m消费者之间的同步是必要的。

你要选择,以便积极生产者和消费者的数量最大化的大部分时间队列的大小。但是,java的线程模型并不能保证任何消费者都会运行,除非它是唯一未被阻止的线程。 (当然,在多核CPU上,消费者很可能会运行)。

1

这取决于你的多线程哲学的本质。对于我们赞成Communicating Sequential Processes的人来说,阻塞队列几乎是完美的。事实上,除非接收器准备好接收消息,否则理想情况将是根本不会将消息放入队列中。

所以,不,我不认为一个阻塞队列违背了多线程的真正目的。事实上,你描述的场景(主线程最终陷入停滞状态)很好地说明了多线程actor模型的主要问题;你不知道它是否会造成死锁/阻塞,你也无法彻底地测试它。

相反,想象一个消息深度为零的阻塞队列。通过这种方式系统可以工作,你必须找到一种方法来确保记录器始终保证能够从主线程接收消息。这是CSP。这可能意味着,在你的假设的记录器线程中,你必须有应用程序定义的缓冲区(而不是某些框架开发人员最好猜测FIFO的深度应该是多少),快速I/O子系统,检查是否跟上,处理方式落后等等。简而言之,它不会让你摆脱困境,你不得不解决系统性能的每个方面。

那是当然的困难,但这样你结束了一个系统,该系统是绝对OK,而不是可疑的“可能”,你有,如果你的阻塞队列深消息的数目不详。