Ograniczona pojemność BlockingQueue
jest również przydatna, jeśli chcesz zmniejszyć przepustowość jakiegoś żądania. Dzięki nieograniczonej kolejce producenci mogą znacznie wyprzedzić konsumentów. Zadania zostaną ostatecznie wykonane (chyba że jest ich tyle, że powodują one OutOfMemoryError
), ale producent już dawno mógł się poddać, więc wysiłek jest marnowany.
W takich sytuacjach lepiej zasygnalizować potencjalnemu producentowi, że kolejka jest pełna, i szybko zrezygnować z błędu. Na przykład producent może być żądaniem sieciowym, z użytkownikiem, który nie chce czekać zbyt długo, i nawet jeśli nie będzie zużywał wielu cykli procesora podczas oczekiwania, zużywa ograniczone zasoby, takie jak gniazdo i pamięć . Rezygnacja sprawi, że zadania, które zostały w kolejce, będą miały większą szansę na zakończenie w odpowiednim czasie.
Odnośnie zmienionego pytania, które interpretuję jako "Jaki jest dobry zbiór do przechowywania obiektów w basenie?"
Bez ograniczeń LinkedBlockingQueue
to dobry wybór dla wielu basenów. Jednak w zależności od strategii zarządzania pulą może również działać ConcurrentLinkedQueue
.
W aplikacji do łączenia blokowanie "wstaw" nie jest właściwe. Kontrolowanie maksymalnego rozmiaru kolejki jest zadaniem menedżera puli, który decyduje, kiedy tworzyć lub niszczyć zasoby puli. Klienci puli pożyczają i zwracają zasoby z puli. Dodanie nowego obiektu lub zwrócenie wcześniej pożyczonego obiektu do puli powinno być szybkimi, nieblokującymi operacjami. Zatem kolejka o ograniczonej pojemności nie jest dobrym wyborem dla pul.
Z drugiej strony podczas pobierania obiektu z puli większość aplikacji chce poczekać, aż zasób będzie dostępny. Operacja "take", która blokuje, przynajmniej tymczasowo, jest znacznie bardziej wydajna niż "ciągłe oczekiwanie", które trwa do momentu, aż zasób będzie dostępny. W tym przypadku dobrym wyborem jest LinkedBlockingQueue
. Kredytobiorca może blokować w nieskończoność z take
lub ograniczyć czas, który chce zablokować z poll
.
Rzadziej spotykany przypadek, gdy klient nie chce blokować w ogóle, ale ma możliwość utworzenia zasobu dla siebie, jeśli pula jest pusta. W takim przypadku dobrym wyborem jest ConcurrentLinkedQueue
. Jest to rodzaj szarego obszaru, w którym byłoby miło dzielić się zasobem (na przykład pamięcią) w jak największym stopniu, ale szybkość jest jeszcze ważniejsza. W gorszym przypadku degeneruje się to do każdej nitki mającej własną instancję zasobu; wtedy byłoby bardziej wydajnie, aby nie zawracać sobie głowy dzieleniem się między wątkami.
Obie te kolekcje zapewniają dobrą wydajność i łatwość użycia w aplikacji współbieżnej. W przypadku aplikacji innych niż współbieżne, trudno jest pokonać numer ArrayList
. Nawet w przypadku kolekcji, które dynamicznie rosną, koszty narzutu w przeliczeniu na elementy w postaci LinkedList
pozwalają na ArrayList
z niektórymi pustymi gniazdami, aby zachować konkurencyjność w pamięci.
Thanks Erickson za taki miły wyjaśnienia. To rozwiązało mój problem. –