Laboratorul 4 - Introducere în Java Multithreading
Spre deosebire de limbajul C unde implementarea unui thread și a mecanismelor de sincronizare depinde de o bibliotecă ce este specifică unui anumit tip de sistem de operare (Linux, Windows, MacOSX), Java oferă suport pentru lucrul cu thread-urile direct din cadrul SDK său.
📄️ Fire de execuție in Java
Implementarea unui nou thread
📄️ Cuvântul cheie synchronized
Cuvântul rezervat synchronized are rolul de a defini blocuri de cod și metode ce reprezintă secțiuni/regiuni critice.
📄️ Clasa CyclicBarrier
Bariera ciclică reprezintă un mecanism de (re)sincronizare a mai multor thread-uri care are scopul de a bloca un număr specificat de thread-uri și de a le lăsa sa își continue execuția într-un mod sincron doar după ce toate au apelat metoda acesteia de resincronizare. În Java, acest mecanism este reprezentat de clasa CyclicBarrier. La instanțierea acesteia, se va specifica numărul de thread-uri pe care aceasta le va resincroniza. Acest mecanism de sincronizare a thread-urilor este util în cazul algoritmilor iterativi ce sunt rulați în paralel și au nevoie de o etapă de resincronizare a firelor de execuție înainte de a trece la noua iterație de calcul. Trebuie ținut cont de faptul că apelul metodei await() pe bariera ciclică poate arunca o excepție de tipul BrokenBarrierException sau InterruptedException.
📄️ Cuvântul cheie volatile
Cuvântul rezervat volatile asociat unei variabile specifică faptul că acea variabilă nu poate fi optimizată (plasată într-un registru sau exclusă din condiții pe baza unor invarianți de la compilare) și fiecare scriere sau citire asociată acesteia se va realiza lucrând cu memoria RAM. Acest lucru este util în prevenirea unor optimizări incompatibile în combinație cu modificarea valorii din alt thread, respectiv a citirii unei date neactualizate din registrul asociat core-ului pe care rulează un thread în momentul în care variabila a căpătat o valoare nouă pe alt thread.
📄️ Variabile atomice
În cadrul laboratorului 2, am observat cum operația de incrementare (exemplul cu instrucțiunea a+=2) nu este o operație atomică (operație ce nu poate fi divizată atunci când este executată de către un thread). Java oferă suport pentru o serie de tipuri de date (tipuri atomice) ce au asociate operații atomice (mai multe detalii aici și aici). Acestea sunt utile pentru a fi folosite pe post de contoare sau acumulatori fără a mai folosi mecanisme de sincronizare.
📄️ Exerciții
1. Creați un program care să lanseze un număr de thread-uri egal cu numărul de core-uri de care dispune calculatorul vostru. Fiecare thread trebuie să afișeze la consolă un text de tipul "Hello from thread #id".