2013-07-05 41 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,而不是可疑的「可能」,你有,如果你的阻塞隊列深消息的數目不詳。