2008-12-11 66 views
16

我想我應該重構我的問題您應該在哪裏使用BlockingQueue實現而不是簡單隊列實現?

您應該在哪裏使用BlockingQueue實現而不是簡單隊列實現?

什麼優點/過Queue實現的BlockingQueue的缺點考慮方面,例如速度,併發或其它特性而變化的例如訪問最後一個元素的時間。

我已經使用了這兩種隊列。我知道阻塞隊列通常用於併發應用程序。我正在編寫簡單的ByteBuffer池,我需要一些ByteBuffer對象的佔位符。我需要最快的線程安全隊列實現。即使有像ListList一樣的實現,其元素的訪問時間不變。

任何人都可以討論BlockingQueue vs隊列vs List實現的優點和缺點嗎?

目前我已經使用ArrayList來保存這些ByteBuffer對象。

我應該使用哪種數據結構來保存這些對象?

回答

26

有限容量BlockingQueue也是有用的,如果你想限制某種請求。憑藉無限的隊列,生產者可以遠遠領先於消費者。這些任務最終會被執行(除非有太多它們會導致OutOfMemoryError),但製片人可能早已放棄,所以這些努力被浪費了。

在這樣的情況下,最好向潛在生產者發出隊列已滿的信號,並迅速放棄故障。例如,生產者可能是一個Web請求,用戶不希望等待太久,即使它在等待期間不會消耗很多CPU週期,但它正在使用有限的資源,如套接字和一些內存。放棄將使已經排隊的任務已經有更好的機會及時完成。


關於修改後的問題,我正在解釋爲「什麼是在池中保存對象的好集合?」

無邊界LinkedBlockingQueue是許多游泳池的不錯選擇。但是,根據您的池管理策略,ConcurrentLinkedQueue也可能工作。

在一個池應用程序中,阻塞「put」是不合適的。控制隊列的最大大小是池管理器的作業,它決定何時創建或銷燬池的資源。游泳池的客戶借用游泳池並返回資源。添加一個新對象或將以前借用的對象返回到池中應該是快速的非阻塞操作。所以,一個有界的容量隊列並不是池的好選擇。

另一方面,從池中檢索對象時,大多數應用程序都希望等待資源可用。至少暫時阻止的「take」操作比「繁忙等待」重複輪詢直到資源可用爲止效率更高。在這種情況下,LinkedBlockingQueue是一個不錯的選擇。借款人可以通過take無限期阻止,或限制其願意阻止的時間爲poll

當一個客戶端根本不願意阻止,但有能力爲自己創建一個資源(如果該池爲空)的情況較少見。在這種情況下,ConcurrentLinkedQueue是一個不錯的選擇。這是一個灰色地帶,它儘可能地共享資源(例如,內存)會很好,但速度更重要。在更糟糕的情況下,這退化爲每個線程都有自己的資源實例;那麼它會更有效率,而不會試圖在線程之間共享。

這兩個集合在併發應用程序中提供了良好的性能和易用性。對於非併發應用程序,ArrayList很難被打敗。即使對於動態增長的集合,LinkedList的每個元素開銷也允許帶有一些空插槽的ArrayList保持競爭性的記憶方式。

+1

感謝埃裏克森這樣一個很好的解釋。 它解決了我的問題。 – 2008-12-12 09:27:10

2

你會在多線程情況下看到BlockingQueue。例如,如果要使用構造函數創建一個參數,則需要傳入BlockingQueue作爲參數以創建ThreadPoolExecutor。根據您傳遞給執行者的隊列類型,其行爲可能會有所不同。

0

BlockingQueue對序列化依賴於彼此的並行操作也很有用。

爲了使一個具體的(雖然有點亂)例如,here是一個實時的病人隊列的Web應用程序,其中callInPatient()需要並聯registerPatientToAppointment()推出了並行測試,但需要等到registerPatientToAppointment()執行callPatientInAtDoctorsOffice()前完成:

public class ClinicPatientQueueAppTest extends ParallelTest { 

    private static final BlockingQueue WAIT_FOR_REGISTRATION_QUEUE = new ArrayBlockingQueue(2); 

    @Test 
    public void callInPatient() { 
     loginToDoctorsOffice("user", "password"); 
     waitUntilRegistrationCompleted(); // <-- 
     callPatientInAtDoctorsOffice(); 
    } 

    @Test 
    public void registerPatientToAppointment() { 
     registerPatientAtRegistrationKiosk("Patient Peter"); 
     notifyRegistrationCompleted(); // <-- 
    } 

    private void waitUntilRegistrationCompleted() { 
     WAIT_FOR_REGISTRATION_QUEUE.take(); 
    } 

    private void notifyRegistrationCompleted() { 
     WAIT_FOR_REGISTRATION_QUEUE.put(this); 
    } 

} 
0

這是一個Queue實現,還支持操作是

等待隊列檢索一個元素,

等待時用於存儲 元件時空間成爲在隊列中可用的變爲非空。

如果你需要以上功能之後,將您Queue實現然後使用Blocking Queue