ThreadPoolExecutor - 1

„Programatorii obișnuiți, mai devreme sau mai târziu, se confruntă cu faptul că au multe sarcini mici care trebuie îndeplinite din când în când.”

„Dacă scrii un joc, atunci sunt acțiunile pe care personajele individuale le efectuează.”

„Dacă scrieți un server web, atunci este vorba despre diferite comenzi care vin de la utilizatori: încărcați o fotografie, transcodați-o în formatul dorit, aplicați șablonul dorit etc.”

„Mai devreme sau mai târziu, toate sarcinile mari sunt împărțite într-un set de sarcini mici, gestionabile.”

„Așadar, având în vedere acest context, apare o întrebare subtilă: cum ar trebui să le gestionați pe toate? Ce se întâmplă dacă trebuie să efectuați câteva sute de sarcini într-un minut? Crearea unui fir pentru fiecare sarcină nu ar avea prea mult sens. Mașina Java alocă destul de multe resurse pentru fiecare fir."

„Cu alte cuvinte, crearea și distrugerea unui fir poate dura mai mult timp și resurse decât sarcina în sine.”

„Creatorii Java au venit cu o soluție elegantă la această problemă: ThreadPoolExecutor .

" ThreadPoolExecutor este o clasă cu două lucruri în interior:"

A)  O coadă de activități, la care puteți adăuga sarcini pe măsură ce apar în program.

B) Un pool de fire, care este un grup de fire care efectuează aceste sarcini.

"Mai mult, firele nu sunt distruse odată ce o sarcină este terminată. În schimb, ele adorm pentru a fi gata să înceapă o nouă sarcină de îndată ce aceasta apare."

„Când creați un ThreadPoolExecutor , puteți seta numărul maxim de fire care trebuie create și numărul maxim de sarcini care pot fi puse în coadă. Cu alte cuvinte, puteți limita numărul de fire de execuție la 10, de exemplu, și numărul de sarcinile puse în coadă la 100.”

„Așa funcționează ThreadPoolExecutor :”

1)  Când adăugați o sarcină nouă, aceasta este plasată la sfârșitul cozii.

2)  Dacă coada este plină, se aruncă o excepție.

3)  La finalizarea unei sarcini, fiecare thread preia următoarea sarcină din coadă și începe să o execute.

4) Dacă nu există sarcini în coadă, un fir intră în stare de repaus până când sunt adăugate sarcini noi.

„Abordarea, în care limităm numărul de fire de lucru, este avantajoasă prin faptul că, cu cât avem mai multe fire, cu atât interferează mai mult între ele. Este mult mai eficient să ai 5-10 fire de lucru și o coadă lungă de sarcini decât pentru a crea 100 de fire pentru un val de sarcini, care vor concura între ele pentru resurse: memorie, timp procesor, acces la baza de date etc."

„Iată un exemplu de ThreadPoolExecutor în acțiune:”

Exemplu
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.
    }
 });
}

"Uh, nu vad..."

„Un obiect ThreadPoolExecutor este creat când este apelată metoda newFixedThreadPool.”

Deci, este foarte ușor de utilizat. De îndată ce adăugați o sarcină la aceasta cu metoda de trimitere, aceasta:

A)  Trezește un fir adormit, dacă există unul, pentru a executa sarcina.

B)  Dacă nu există un fir în așteptare, atunci creează unul nou pentru sarcină.

C)  Dacă este atins numărul maxim de fire, atunci pur și simplu pune sarcina la sfârșitul cozii.

„Am inclus în mod deliberat „aici descarcăm ceva mare de pe Internet” în exemplu. Dacă avem 100 de sarcini „descărcăm ceva mare de pe Internet”, atunci nu are sens să rulăm multe dintre ele în același timp — noi” Va fi reținut de limita lățimii de bandă a conexiunii noastre la internet. În acest caz, ar trebui să fie suficiente câteva fire. Acesta este ceea ce vedeți în exemplul de mai sus:"

ExecutorService service = Executors.newFixedThreadPool(2);

„Se pare că lucrul cu o grămadă de sarcini nu este atât de dificil”.

— Da. Chiar mai uşor decât ţi-ai putea imagina. Dar Kim îţi va spune despre asta.