ThreadPoolExecutor - 1

„Zwykli programiści prędzej czy później oswajają się z faktem, że mają wiele drobnych zadań, które trzeba od czasu do czasu wykonać”.

„Jeśli piszesz grę, to są to działania, które wykonują poszczególne postacie”.

„Jeśli piszesz serwer WWW, to różne polecenia przychodzą od użytkowników: prześlij zdjęcie, transkoduj je do żądanego formatu, zastosuj żądany szablon itp.”

„Prędzej czy później wszystkie duże zadania są dzielone na zestaw małych, łatwych do wykonania zadań”.

„Tak więc, biorąc pod uwagę ten kontekst, pojawia się subtelne pytanie: jak masz zarządzać nimi wszystkimi? A co, jeśli musisz wykonać kilkaset zadań w ciągu minuty? Tworzenie wątku dla każdego zadania nie miałoby większego sensu. Maszyna Java przydziela dość dużo zasobów dla każdego wątku.”

„Innymi słowy, tworzenie i niszczenie wątku może zająć więcej czasu i zasobów niż samo zadanie”.

„Twórcy Javy wymyślili eleganckie rozwiązanie tego problemu: ThreadPoolExecutor .

ThreadPoolExecutor to klasa zawierająca dwie rzeczy:”

A)  Kolejka zadań, do której można dodawać zadania w miarę ich powstawania w programie.

B) Pula wątków, która jest grupą wątków wykonujących te zadania.

„Co więcej, wątki nie są niszczone po zakończeniu zadania. Zamiast tego zasypiają, aby być gotowym do rozpoczęcia nowego zadania, gdy tylko się pojawi”.

„Kiedy tworzysz ThreadPoolExecutor , możesz ustawić maksymalną liczbę wątków do utworzenia i maksymalną liczbę zadań, które można ustawić w kolejce. Innymi słowy, możesz ograniczyć liczbę wątków na przykład do 10, a liczbę zadań w kolejce do 100”.

„Tak działa ThreadPoolExecutor :”

1)  Kiedy dodajesz nowe zadanie, jest ono umieszczane na końcu kolejki.

2)  Jeśli kolejka jest pełna, zgłaszany jest wyjątek.

3)  Po wykonaniu zadania każdy wątek pobiera następne zadanie z kolejki i zaczyna je wykonywać.

4) Jeśli w kolejce nie ma żadnych zadań, wątek przechodzi w stan uśpienia do czasu dodania nowych zadań.

„Podejście, w którym ograniczamy liczbę wątków roboczych, jest korzystne w tym sensie, że im więcej mamy wątków, tym bardziej wzajemnie sobie przeszkadzają. O wiele bardziej efektywne jest posiadanie 5-10 wątków roboczych i długiej kolejki zadań niż stworzyć 100 wątków dla fali zadań, które będą konkurować ze sobą o zasoby: pamięć, czas procesora, dostęp do bazy danych itp.”

„Oto przykład ThreadPoolExecutor w akcji:”

Przykład
ExecutorService service = Executors.newFixedThreadPool(2);

for(int i = 0; i < 10; i++)
{
 service.submit(new Runnable() {
    public void run()
    {
     // Here we download something big from the Internet.
    }
 });
}

— Eee, nie widzę…

„ Obiekt ThreadPoolExecutor jest tworzony, gdy wywoływana jest metoda newFixedThreadPool”.

Jest więc bardzo łatwy w użyciu. Gdy tylko dodasz do niego zadanie za pomocą metody przesyłania:

A)  Budzi uśpiony wątek, jeśli taki istnieje, w celu wykonania zadania.

B)  Jeśli nie ma oczekującego wątku, tworzy nowy dla zadania.

C)  Jeśli zostanie osiągnięta maksymalna liczba wątków, po prostu umieszcza zadanie na końcu kolejki.

„Celowo umieściłem w przykładzie «tutaj pobieramy coś dużego z Internetu». Jeśli mamy 100 zadań «pobierz coś dużego z Internetu», to nie ma sensu uruchamiać wielu z nich w tym samym czasie — my' będzie ograniczany przez limit przepustowości naszego połączenia internetowego. W takim przypadku wystarczy kilka wątków. Oto, co widzisz w powyższym przykładzie:"

ExecutorService service = Executors.newFixedThreadPool(2);

„Okazuje się, że praca z wieloma zadaniami nie jest taka trudna”.

„Tak. Nawet łatwiejsze, niż możesz sobie wyobrazić. Ale Kim ci o tym powie”.