Multithreading în Java Tutorial cu exemple

Cuprins:

Anonim

Orice aplicație poate avea mai multe procese (instanțe). Fiecare din acest proces poate fi atribuit fie ca un singur fir, fie ca mai multe fire. Vom vedea în acest tutorial cum să efectuați mai multe sarcini în același timp și, de asemenea, să aflați mai multe despre fire și sincronizarea între fire.

În acest tutorial, vom învăța:

  • Ce este firul unic
  • Ce este Multithreading în Java?
  • Ciclul de viață al firului în Java
  • Sincronizarea firului Java
  • Exemplu Java Multithreading

Ce este firul unic?

Un singur fir este practic o unitate ușoară și cea mai mică de procesare. Java folosește fire utilizând o „clasă de fire”.

Există două tipuri de fire - fire de utilizator și fire de demon (fire de demon sunt folosite atunci când vrem să curățăm aplicația și sunt utilizate în fundal).

Când începe o aplicație, se creează firul de utilizator. Postați asta, putem crea multe fire de utilizator și fire de demon.

Exemplu de fir unic:

demotest pachet;clasa publică GuruThread{public static main main (String [] args) {System.out.println ("fir unic");}}

Avantajele firului unic:

  • Reduce cheltuielile generale ale aplicației pe măsură ce se execută un singur fir în sistem
  • De asemenea, reduce costul de întreținere al aplicației.

Ce este Multithreading în Java?

MULTITHREADING în Java este un proces de executare simultană a două sau mai multe fire pentru o utilizare maximă a procesorului. Aplicațiile cu mai multe fire execută două sau mai multe fire de rulare simultan. Prin urmare, este, de asemenea, cunoscut sub numele de simultanitate în Java. Fiecare fir rulează paralel unul cu celălalt. Firele de tip mulitple nu alocă zonă de memorie separată, prin urmare economisesc memorie. De asemenea, schimbarea contextului între fire durează mai puțin timp.

Exemplu de multi thread:

demotest pachet;clasa publică GuruThread1 implementează Runnable{public static main main (String [] args) {Fir guruThread1 = fir nou ("Guru1");Fir guruThread2 = fir nou ("Guru2");guruThread1.start ();guruThread2.start ();System.out.println ("Numele firelor sunt următoarele:");System.out.println (guruThread1.getName ());System.out.println (guruThread2.getName ());}@Trece pestepublic void run () {}}

Avantajele multithread-ului:

  • Utilizatorii nu sunt blocați, deoarece firele sunt independente și putem efectua operații multiple uneori
  • Ca atare firele sunt independente, celelalte fire nu vor fi afectate dacă un fir întâlnește o excepție.

Ciclul de viață al firului în Java

Ciclul de viață al unui thread:

Există diferite etape ale ciclului de viață al firului așa cum se arată în diagrama de mai sus:

  1. Nou
  2. Runable
  3. Alergare
  4. Aşteptare
  5. Mort
  1. Nou: În această fază, firul este creat folosind clasa „Clasa firului”. Rămâne în această stare până când programul pornește firul. Este, de asemenea, cunoscut sub numele de fir născut.
  2. Runnable: În această pagină, instanța firului este invocată cu o metodă de pornire. Controlul firului este dat planificatorului pentru a termina execuția. Depinde de planificator, dacă se execută firul.
  3. Rularea: Când firul începe să se execute, atunci starea se schimbă în starea „rulează”. Planificatorul selectează un fir din grupul de fire și începe să se execute în aplicație.
  4. În așteptare: Aceasta este starea în care un fir trebuie să aștepte. Deoarece există mai multe fire de execuție în aplicație, este nevoie de sincronizare între thread-uri. Prin urmare, un fir trebuie să aștepte, până când celălalt fir este executat. Prin urmare, această stare este denumită stare de așteptare.
  5. Dead: Aceasta este starea la care firul este terminat. Firul este în stare de rulare și imediat ce a finalizat procesarea, acesta este în „stare moartă”.

Unele dintre metodele utilizate în mod obișnuit pentru fire sunt:

Metodă Descriere
start() Această metodă pornește executarea firului și JVM apelează metoda run () pe fir.
Somn (în milisecunde) Această metodă face firul să adoarmă, prin urmare execuția firului se va întrerupe pentru milisecunde furnizate și după aceea, din nou firul începe să se execute. Acest ajutor în sincronizarea firelor.
getName () Întoarce numele firului.
setPriority (int newpriority) Schimbă prioritatea firului.
Randament () Provoacă executarea firului curent și a altor fire de executare.

Exemplu: În acest exemplu vom crea un thread și vom explora metodele încorporate disponibile pentru thread-uri.

demotest pachet;clasa publică thread_example1 implementează Runnable {@Trece pestepublic void run () {}public static main main (String [] args) {Fir guruthread1 = fir nou ();guruthread1.start ();încerca {guruthread1.sleep (1000);} catch (InterruptedException e) {// TODO Bloc de captare generat automate.printStackTrace ();}guruthread1.setPriority (1);int gurupriority = guruthread1.getPriority ();System.out.println (guruprioritate);System.out.println ("Executarea firului");}}

Explicația codului:

  • Linia de cod 2: creăm o clasă „thread_Example1” care implementează interfața Runnable (ar trebui implementată de orice clasă ale cărei instanțe sunt destinate a fi executate de thread.)
  • Linia de cod 4: Înlocuiește metoda de rulare a interfeței rulabile, deoarece este obligatoriu să înlocuiți acea metodă
  • Linia de cod 6: Aici am definit metoda principală în care vom începe executarea firului.
  • Linia de cod 7: Aici creăm un nou nume de fir ca „guruthread1” prin crearea unei noi clase de fire.
  • Linia de cod 8: vom folosi metoda „start” a firului utilizând instanța „guruthread1”. Aici firul va începe să se execute.
  • Linia de cod 10: Aici utilizăm metoda „sleep” a firului utilizând instanța „guruthread1”. Prin urmare, firul va dormi 1000 de milisecunde.
  • Cod 9-14: Aici am pus metoda sleep în blocul try catch, deoarece există o excepție verificată, care apare, adică excepția întreruptă.
  • Linia de cod 15: Aici stabilim prioritatea firului la 1 din oricare dintre priorități
  • Linia de cod 16: Aici primim prioritatea firului folosind getPriority ()
  • Linia de cod 17: Aici imprimăm valoarea preluată din getPriority
  • Linia de cod 18: Aici scriem un text pe care rulează firul.

Când executați codul de mai sus, obțineți următoarea ieșire:

Ieșire:

5 este prioritatea Thread, iar Thread Running este textul care este rezultatul codului nostru.

Sincronizarea firului Java

În multithreading, există comportamentul asincron al programelor. Dacă un fir scrie anumite date și un alt fir care citește date în același timp, ar putea crea neconcordanță în aplicație.

Când este nevoie să accesați resursele partajate de două sau mai multe fire, atunci se utilizează abordarea de sincronizare.

Java a furnizat metode sincronizate pentru a implementa comportamentul sincronizat.

În această abordare, odată ce firul ajunge în interiorul blocului sincronizat, atunci niciun alt fir nu poate apela acea metodă pe același obiect. Toate firele trebuie să aștepte până când acel fir termină blocul sincronizat și iese din acesta.

În acest fel, sincronizarea ajută într-o aplicație cu mai multe fire. Un fir trebuie să aștepte până când celălalt fir își termină execuția numai atunci celelalte fire sunt permise pentru executare.

Poate fi scris în următoarea formă:

Sincronizat (obiect){// Bloc de instrucțiuni care trebuie sincronizat}

Exemplu Java Multithreading

În acest exemplu, vom lua două fire și vom prelua numele firului.

Exemplul 1:

GuruThread1.javademotest pachet;clasa publică GuruThread1 implementează Runnable {/ *** @param args* /public static main main (String [] args) {Fir guruThread1 = fir nou ("Guru1");Fir guruThread2 = fir nou ("Guru2");guruThread1.start ();guruThread2.start ();System.out.println ("Numele firelor sunt următoarele:");System.out.println (guruThread1.getName ());System.out.println (guruThread2.getName ());}@Trece pestepublic void run () {}}

Explicația codului:

  • Linia de cod 3: Am luat o clasă "GuruThread1" care implementează Runnable (ar trebui să fie implementată de orice clasă ale cărei instanțe sunt destinate a fi executate de thread.)
  • Linia de cod 8: Aceasta este principala metodă a clasei
  • Linia de cod 9: Aici instantăm clasa Thread și creăm o instanță denumită „guruThread1” și creăm un thread.
  • Linia de cod 10: Aici instantăm clasa Thread și creăm o instanță numită „guruThread2” și creăm un thread.
  • Linia de cod 11: Începem firul, adică guruThread1.
  • Linia de cod 12: Începem firul, adică guruThread2.
  • Linia de cod 13: Trimiterea textului ca „Numele firelor sunt următoarele:”
  • Linia de cod 14: Obținerea numelui firului 1 utilizând metoda getName () a clasei de fire.
  • Linia de cod 15: Obținerea numelui firului 2 utilizând metoda getName () a clasei de fire.

Când executați codul de mai sus, obțineți următoarea ieșire:

Ieșire:

Numele firelor sunt scoase aici ca

  • Guru1
  • Guru2

Exemplul 2:

În acest exemplu, vom afla despre metodele de suprascriere run () și start () metoda unei interfețe rulabile și vom crea două fire din acea clasă și le vom executa în consecință.

De asemenea, luăm două clase,

  • Unul care va implementa interfața rulabilă și
  • Un altul care va avea metoda principală și se va executa corespunzător.
demotest pachet;clasă publică GuruThread2 {public static main main (String [] args) {// TODO Metoda generată automatGuruThread3 threadguru1 = nou GuruThread3 („guru1”);threadguru1.start ();GuruThread3 threadguru2 = nou GuruThread3 („guru2”);threadguru2.start ();}}clasa GuruThread3 implementează Runnable {Filul guruthread;privat Strun guruname;GuruThread3 (numele șirului) {guruname = nume;}@Trece pestepublic void run () {System.out.println ("Executarea firului" + guruname);for (int i = 0; i <4; i ++) {System.out.println (i);System.out.println (guruname);încerca {Thread.sleep (1000);} catch (InterruptedException e) {System.out.println ("Firul a fost întrerupt");}}}public void start () {System.out.println ("Firul a început");if (guruthread == nul) {guruthread = fir nou (acesta, guruname);guruthread.start ();}}}

Explicația codului:

  • Linia de cod 2: Aici luăm o clasă "GuruThread2" care va avea metoda principală în ea.
  • Linia de cod 4: Aici luăm o metodă principală a clasei.
  • Linia de cod 6-7: Aici creăm o instanță a clasei GuruThread3 (care este creată în rândurile de mai jos ale codului) ca „threadguru1” și începem firul.
  • Linia de cod 8-9: Aici creăm o altă instanță a clasei GuruThread3 (care este creată în rândurile de mai jos ale codului) ca „threadguru2” și începem firul.
  • Linia de cod 11: Aici creăm o clasă "GuruThread3" care implementează interfața rulabilă (ar trebui să fie implementată de orice clasă ale cărei instanțe sunt destinate a fi executate de thread.)
  • Linia de cod 13-14: luăm două variabile de clasă din care una este de tip fir de clasă și alta de clasă de șir.
  • Linia de cod 15-18: anulăm constructorul GuruThread3, care ia un argument ca tip de șir (care este numele firelor) care este atribuit variabilei de clasă guruname și, prin urmare, este stocat numele firului.
  • Linia de cod 20: Aici anulăm metoda run () a interfeței rulabile.
  • Linia de cod 21: scoatem numele firului folosind instrucțiunea println.
  • Linia de cod 22-31: Aici folosim o buclă for cu contor inițializat la 0 și nu ar trebui să fie mai mică de 4 (putem lua orice număr, prin urmare aici bucla va rula de 4 ori) și incrementând contorul. Tipărim numele firului și, de asemenea, facem firul să adoarmă timp de 1000 de milisecunde într-un bloc try-catch, deoarece metoda de repaus a ridicat verificarea excepției.
  • Linia de cod 33: Aici trecem la metoda de pornire a interfeței rulabile.
  • Linia de cod 35: Trimitem textul „Firul a început”.
  • Linia de cod 36-40: Aici luăm o condiție if pentru a verifica dacă variabila de clasă guruthread are valoare în ea sau nu. Dacă este nulă, atunci creăm o instanță folosind clasa de fir care ia numele ca parametru (valoarea pentru care a fost atribuită în constructor). După care firul este început folosind metoda start ().

Când executați codul de mai sus, obțineți următoarea ieșire:

Ieșire :

Prin urmare, există două fire, primim de două ori mesajul „Firul a început”.

Primim numele firului pe măsură ce le-am dat.

Merge în buclă unde tipărim contorul și numele firului și contorul începe cu 0.

Bucla se execută de trei ori și între fir este oprit timp de 1000 de milisecunde.

Prin urmare, mai întâi, obținem guru1 apoi guru2 apoi din nou guru2 deoarece firul doarme aici 1000 de milisecunde și apoi următorul guru1 și din nou guru1, firul doarme 1000 de milisecunde, așa că primim guru2 și apoi guru1.

Rezumat :

În acest tutorial, am văzut aplicații multithread în Java și cum se utilizează fire individuale și multiple.

  • În multithreading, utilizatorii nu sunt blocați, deoarece firele sunt independente și pot efectua mai multe operații în același timp
  • Diferite etape ale ciclului de viață al firului sunt,
    • Nou
    • Runable
    • Alergare
    • Aşteptare
    • Mort
  • De asemenea, am aflat despre sincronizarea între fire, care ajută aplicația să ruleze fără probleme.
  • Multithreading facilitează mult mai multe sarcini ale aplicației.