Multithreading în Java
Orice aplicație poate avea mai multe procese (instanțe). Fiecare dintre 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, vom afla mai multe despre fire și sincronizare între fire.
Ce este un singur fir?
Un singur fir înăuntru Java este practic o unitate ușoară și cea mai mică de procesare. Java folosește fire folosind o „Clasă de fire”. Există două tipuri de fire - fir de utilizator și fir de demon (Firele daemon sunt folosite atunci când vrem să curățăm aplicația și sunt folosite în fundal). Când o aplicație începe pentru prima dată, este creat un fir de utilizator. După asta, putem crea multe fire de utilizare și fire de demon.
Exemplu cu un singur fir:
package demotest; public class GuruThread { public static void main(String[] args) { System.out.println("Single Thread"); } }
Avantajele unui singur fir:
- Reduce supraîncărcarea în aplicație pe măsură ce un singur thread se execută în sistem
- De asemenea, reduce costul de întreținere al aplicației.
În ce este Multithreadingul Java?
multithreading in Java este un proces de executare a două sau mai multe fire de execuție simultan pentru utilizarea maximă a procesorului. Aplicațiile cu mai multe fire execută două sau mai multe fire care rulează simultan. Prin urmare, este cunoscut și sub numele de Concurrency în Java. Fiecare fir rulează paralel unul cu celălalt. Firele multiple nu alocă o zonă de memorie separată, prin urmare economisesc memorie. De asemenea, schimbarea contextului între fire durează mai puțin timp.
Exemplu de fire multiple:
package demotest; public class GuruThread1 implements Runnable { public static void main(String[] args) { Thread guruThread1 = new Thread("Guru1"); Thread guruThread2 = new Thread("Guru2"); guruThread1.start(); guruThread2.start(); System.out.println("Thread names are following:"); System.out.println(guruThread1.getName()); System.out.println(guruThread2.getName()); } @Override public void run() { } }
Avantajele multithread:
- Utilizatorii nu sunt blocați deoarece firele sunt independente și putem efectua mai multe operații uneori
- Ca atare firele sunt independente, celelalte fire nu vor fi afectate dacă un fir îndeplinește o excepție.
Ciclul de viață al filetului în Java
Ciclul de viață al unui fir:
Există diferite etape ale ciclului de viață al firului, așa cum se arată în diagrama de mai sus:
- Nou
- Rugabil
- Alergare
- Aşteptare
- Mort
- Nou: În această fază, thread-ul este creat folosind clasa „Thread class”. Acesta rămâne în această stare până la program începe firul. Este cunoscut și sub numele de fir născut.
- Rugabil: În această pagină, instanța firului de execuție este invocată cu o metodă de pornire. Controlul firului este dat planificatorului pentru a termina execuția. Depinde de programator, dacă să ruleze firul.
- Alergare: Când firul începe să se execute, atunci starea este schimbată în starea „în rulare”. Programatorul selectează un fir din pool-ul de fire și începe să se execute în aplicație.
- Aşteptare: Aceasta este starea în care un thread trebuie să aștepte. Deoarece în aplicație rulează mai multe fire de execuție, este nevoie de sincronizare între fire. Prin urmare, un thread trebuie să aștepte, până când celălalt thread este executat. Prin urmare, această stare este denumită stare de așteptare.
- Mort: Aceasta este starea în care firul este terminat. Firul este în stare de rulare și de îndată ce a finalizat procesarea este în „stare moartă”.
Metode de multithreading în Java
Unele dintre metodele frecvent utilizate pentru fire sunt:Metodă | Descriere |
---|---|
start() | Această metodă începe execuția firului și FMV apelează metoda run() pe fir. |
Sleep (înt milisecunde) | Această metodă face ca firul să dorm, prin urmare, execuția firului se va întrerupe pentru milisecunde furnizate și după aceea, din nou firul începe să se execute. Acest lucru ajută la sincronizarea firelor. |
getName () | Returnează numele firului. |
setPriority(int newpriority) | Schimbă prioritatea firului. |
Randament () | Determină firul curent la oprire și executarea altor fire. |
Exemplu: În acest program multithreading în Java De exemplu, vom crea un fir și vom explora metodele încorporate disponibile pentru fire.
package demotest; public class thread_example1 implements Runnable { @Override public void run() { } public static void main(String[] args) { Thread guruthread1 = new Thread(); guruthread1.start(); try { guruthread1.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } guruthread1.setPriority(1); int gurupriority = guruthread1.getPriority(); System.out.println(gurupriority); System.out.println("Thread Running"); } }
Explicația codului:
- Linia de cod 2: Creăm o clasă „thread_Example1” care implementează interfața Runnable (ar trebui să fie implementată de orice clasă ale cărei instanțe sunt destinate să fie executate de fir.)
- Linia de cod 4: Ea suprascrie metoda de rulare a interfeței rulabile, deoarece este obligatoriu să se suprascrie acea metodă
- Linia de cod 6: Aici am definit metoda principală în care vom începe execuția firului.
- Linia de cod 7: Aici creăm un nou nume de fir ca „guruthread1” prin instanțierea unei noi clase de fir.
- Linia de cod 8: vom folosi metoda „start” a firului folosind instanța „guruthread1”. Aici thread-ul va începe să se execute.
- Linia de cod 10: Aici folosim metoda „sleep” a firului folosind instanța „guruthread1”. Prin urmare, firul va dormi timp de 1000 de milisecunde.
- Cod 9-14: Aici am pus metoda sleep în blocul try catch, deoarece există o excepție verificată care apare, adică o excepție întreruptă.
- Linia de cod 15: Aici setăm prioritatea firului de execuție la 1, indiferent de prioritate
- Linia de cod 16: Aici obținem prioritatea firului folosind getPriority()
- Linia de cod 17: Aici tipărim valoarea preluată de la getPriority
- Linia de cod 18: Aici scriem un text pe care firul rulează.
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.
Java Fir Synchronizare
În multithreading, există comportamentul asincron al programelor. Dacă un fir de execuție scrie unele date și un alt fir care citește date în același timp, ar putea crea inconsecvență în aplicație. Când este nevoie să accesați resursele partajate de două sau mai multe fire de execuție, 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 thread termină blocul sincronizat și iese din acesta. În acest fel, sincronizarea ajută într-o aplicație multithreaded. Un fir de execuție trebuie să aștepte până când celălalt fir de execuție își termină execuția, numai atunci celelalte fire sunt permise pentru execuție.
Se poate scrie sub următoarea formă:
Synchronized(object) { //Block of statements to be synchronized }
Multithreading în Java Exemple de programe
În acest multithreading Java de exemplu, vom lua două fire și vom prelua numele firului.
Example1:
GuruThread1.java package demotest; public class GuruThread1 implements Runnable{ /** * @param args */ public static void main(String[] args) { Thread guruThread1 = new Thread("Guru1"); Thread guruThread2 = new Thread("Guru2"); guruThread1.start(); guruThread2.start(); System.out.println("Thread names are following:"); System.out.println(guruThread1.getName()); System.out.println(guruThread2.getName()); } @Override public 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 să fie executate de fir.)
- Linia de cod 8: Aceasta este metoda principală a clasei
- Linia de cod 9: Aici instanțiem clasa Thread și creăm o instanță numită „guruThread1” și creăm un fir.
- Linia de cod 10: Aici instanțiem clasa Thread și creăm o instanță numită „guruThread2” și creăm un fir.
- Linia de cod 11: Începem firul, adică guruThread1.
- Linia de cod 12: Începem firul, adică guruThread2.
- Linia de cod 13: Ieșirea textului ca „Numele firelor sunt următoarele:”
- Linia de cod 14: Obținerea numelui firului 1 folosind metoda getName() a clasei thread.
- Linia de cod 15: Obținerea numelui firului 2 folosind metoda getName() a clasei thread.
Când executați codul de mai sus, obțineți următoarea ieșire:
ieșire:
Numele firelor sunt afișate aici ca
- Guru1
- Guru2
Exemplu 2:
În acest multithreading în Java De exemplu, vom afla despre suprascrierea metodelor run() și start() a unei interfețe rulabile și vom crea două fire de execuție ale acelei clase și le vom rula în consecință.
De asemenea, luăm două cursuri,
- Una care va implementa interfața rulabilă și
- Un altul care va avea metoda principală și se va executa în consecință.
package demotest; public class GuruThread2 { public static void main(String[] args) { // TODO Auto-generated method stub GuruThread3 threadguru1 = new GuruThread3("guru1"); threadguru1.start(); GuruThread3 threadguru2 = new GuruThread3("guru2"); threadguru2.start(); } } class GuruThread3 implements Runnable { Thread guruthread; private String guruname; GuruThread3(String name) { guruname = name; } @Override public void run() { System.out.println("Thread running" + guruname); for (int i = 0; i < 4; i++) { System.out.println(i); System.out.println(guruname); try { Thread.sleep(1000); } catch (InterruptedException e) { System.out.println("Thread has been interrupted"); } } } public void start() { System.out.println("Thread started"); if (guruthread == null) { guruthread = new Thread(this, 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 să fie executate de fir.)
- Linia de cod 13-14: luăm două variabile de clasă din care una este de tip thread class și alta din clasa șir.
- Linia de cod 15-18: suprascriem constructorul GuruThread3, care ia un argument ca tip șir (care este numele firelor) care este atribuit variabilei de clasă guruname și, prin urmare, numele firului este stocat.
- Linia de cod 20: Aici suprascriem metoda run() a interfeței rulabile.
- Linia de cod 21: Emitem numele firului folosind instrucțiunea println.
- Linia de cod 22-31: Aici folosim o buclă for cu contorul inițializat la 0 și nu ar trebui să fie mai mic de 4 (putem lua orice număr, deci aici bucla va rula de 4 ori) și incrementăm contorul. Tipărim numele firului de execuție și, de asemenea, facem ca firul de execuție să intre timp de 1000 de milisecunde într-un bloc try-catch, deoarece metoda de repaus a ridicat excepția bifată.
- Linia de cod 33: Aici suprascriem metoda de pornire a interfeței rulabile.
- Linia de cod 35: Afișăm textul „Thread început”.
- Linia de cod 36-40: Aici luăm o condiție if pentru a verifica dacă variabila de clasă guruthread are valoare sau nu. Dacă este nul, atunci creăm o instanță folosind clasa de fir care ia numele ca parametru (valoare pentru care a fost atribuită în constructor). După care firul este pornit folosind metoda start().
Când executați codul de mai sus, obțineți următoarea ieșire:
producție:
Prin urmare, există două fire, primim mesajul de două ori „Thread started”.
Obținem numele firului așa cum le-am scos.
Intră în bucla for, unde tipărim contorul și numele firului, iar contorul începe cu 0.
Bucla se execută de trei ori și între fire este adormit timp de 1000 de milisecunde.
Prin urmare, mai întâi, obținem guru1 apoi guru2 apoi din nou guru2 pentru că firul doarme aici timp de 1000 de milisecunde și apoi următorul guru1 și din nou guru1, firul doarme timp de 1000 de milisecunde, deci obținem guru2 și apoi guru1.
Rezumat
În acest tutorial, am văzut aplicații multithreaded în Java și cum să utilizați un fir și mai multe fire în Java.
- Explicați multithreading în Java: în multithreading, utilizatorii nu sunt blocați, deoarece firele sunt independente și pot efectua mai multe operații în același timp
- Diverse etape ale ciclului de viață al firului sunt:
- Nou
- Rugabil
- Alergare
- Aşteptare
- Mort
- Am aflat și noi despre sincronizare între fire, care ajută aplicația să ruleze fără probleme.
- Programare cu mai multe fire în Java ușurează multe mai multe sarcini de aplicație.