Uvod u sinkronizaciju na Javi

Sinkronizacija je značajka Java koja ograničava više niti jednog pokušaja pristupa zajedničkim zajedničkim resursima istovremeno. Ovdje se dijeljeni resursi odnose na sadržaj vanjske datoteke, varijable klase ili zapise baze podataka.

Sinkronizacija se široko koristi u višečlanom programiranju. "Sinkronizirano" je ključna riječ koja vašem kôdu omogućuje mogućnost da samo jedan nit radi na njemu bez smetnji od bilo koje druge niti tijekom tog razdoblja.

Zašto nam je potrebna sinkronizacija u Javi?

  • Java je programski jezik s više niti. To znači da dvije ili više niti može istodobno krenuti prema ispunjenju zadatka. Kada se niti pokreću istovremeno, velike su šanse da će se dogoditi scenarij u kojem bi vaš kôd mogao pružiti neočekivane ishode.
  • Možda se pitate da ako multithreading može uzrokovati pogrešne izlaze, zašto se onda to smatra važnom značajkom u Javi?
  • Multithreading ubrzava vaš kôd paralelnim pokretanjem više niti i na taj način smanjuje vrijeme izvršenja koda i pruža visoku učinkovitost. Međutim, korištenje okoliša s višestrukim navojem dovodi do netočnih rezultata zbog stanja općenito poznatog kao trkački uvjet.

Što je uvjet za utrku?

Kad se dvije ili više niti pokreće paralelno, oni imaju pristup i mijenjaju zajedničke resurse u tom trenutku. Sekvence u kojima se izvršavaju niti odlučuju algoritam za planiranje niti.

Zbog toga se ne može predvidjeti redoslijed izvršavanja niti, jer njime upravlja isključivo planer niti. To utječe na izlaz koda i rezultira nedosljednim izlazima. Budući da se za završetak operacije utrkuje više niti jedni sa drugima, uvjet se naziva "trkački uvjet".

Na primjer, razmotrimo donji kôd:

Class Modify:
package JavaConcepts;
public class Modify implements Runnable(
private int myVar=0;
public int getMyVar() (
return myVar;
)
public void setMyVar(int myVar) (
this.myVar = myVar;
)
public void increment() (
myVar++;
)
@Override
public void run() (
// TODO Auto-generated method stub
this.increment();
System.out.println("Current thread being executed "+ Thread.currentThread().getName() + "Current Thread value " + this.getMyVar());
)
)
Class RaceCondition:
package JavaConcepts;
public class RaceCondition (
public static void main(String() args) (
Modify mObj = new Modify();
Thread t1 = new Thread(mObj, "thread 1");
Thread t2 = new Thread(mObj, "thread 2");
Thread t3 = new Thread(mObj, "thread 3");
t1.start();
t2.start();
t3.start();
)
)

Na uzastopnom izvođenju gornjeg koda, rezultati će biti sljedeći:

Ourput1:

Sadašnji navoj se izvršava nit 1 Trenutna vrijednost navoja 3

Sadašnji navoj se izvršava nit 3 Trenutna vrijednost navoja 2

Sadašnji navoj se izvršava nit 2 Trenutna vrijednost navoja 3

Output2:

Sadašnji navoj se izvršava nit 3 Trenutna vrijednost navoja 3

Sadašnji navoj se izvršava nit 2 Trenutna vrijednost navoja 3

Sadašnji navoj se izvršava nit 1 Trenutna vrijednost navoja 3

Output3:

Sadašnji navoj se izvršava nit 2 Trenutna vrijednost navoja 3

Sadašnji navoj se izvršava nit 1 Trenutna vrijednost navoja 3

Sadašnji navoj se izvršava nit 3 Trenutna vrijednost navoja 3

Output4:

Sadašnji navoj se izvršava nit 1 Trenutna vrijednost navoja 2

Sadašnji navoj se izvršava nit 3 Trenutna vrijednost navoja 3

Sadašnji navoj se izvodi nit 2 Trenutna vrijednost navoja 2

  • Iz gornjeg primjera možete zaključiti da se niti izvršavaju nasumično i da je vrijednost netočna. Prema našoj logici, vrijednost treba povećati za 1. Međutim, ovdje je vrijednost izlaza u većini slučajeva 3, a u nekoliko slučajeva to je 2.
  • Ovdje je varijabla "myVar" zajednički resurs na kojem se vrši više niti. Teme istovremeno pristupaju i mijenjaju vrijednost "myVar". Pogledajmo što će se dogoditi ako komentiramo druga dva teme.

Izlaz u ovom slučaju je:

Aktualni navoj koji se izvodi nit 1 Trenutna vrijednost navoja 1

To znači da, kada pojedinačna nit radi, izlaz je onakav kakav se očekivalo. Međutim, kada se pokreće više niti, vrijednost se mijenja svakom niti. Stoga treba ograničiti broj niti koji rade na zajedničkom resoru na jednu nit. To se postiže sinkronizacijom.

Razumijevanje Što je sinkronizacija u Javi

  • Sinkronizacija u Javi se postiže pomoću ključne riječi "sinkronizirano". Ova se ključna riječ može koristiti za metode ili blokove ili objekte, ali ne može se koristiti s klasama i varijablama. Sinkronizirani dio koda omogućuje samo jednoj niti da joj pristupi i modificira u određenom trenutku.
  • Međutim, sinkronizirani dio koda utječe na performanse koda jer povećava vrijeme čekanja ostalih niti kojima pokušavaju pristupiti. Dakle, dio koda trebao bi se sinkronizirati samo kad postoji šansa da se pojavi stanje utrke. Ako ne, nitko ga ne bi trebao izbjegavati.

Kako sinkronizacija u Javi djeluje interno?

  • Unutarnja sinkronizacija u Javi implementirana je uz pomoć zaključavanja (poznatog i kao monitor). Svaki Java objekt ima svoju bravu. U sinkroniziranom bloku koda, nit mora steći bravu prije nego što bude u mogućnosti izvršiti taj određeni blok koda. Jednom kada nit zaključa zaključavanje, može izvršiti taj dio koda.
  • Po završetku izvršenja, brava se automatski oslobađa. Ako neki drugi nit zahtijeva rad na sinkroniziranom kodu, čeka trenutni navoj koji djeluje na njemu da otpusti bravu. Za ovaj postupak stjecanja i oslobađanja brave interno se brine Java virtualni stroj. Program nije odgovoran za nabavu i oslobađanje brave od strane navoja. Preostale teme mogu, međutim, istovremeno izvršavati bilo koji drugi nesinkronizirani dio koda.

Sinhronizirajmo naš prethodni primjer sinkroniziranjem koda unutar metode izvođenja pomoću sinkroniziranog bloka u klasi „Izmijeni“, kako slijedi:

Class Modify:
package JavaConcepts;
public class Modify implements Runnable(
private int myVar=0;
public int getMyVar() (
return myVar;
)
public void setMyVar(int myVar) (
this.myVar = myVar;
)
public void increment() (
myVar++;
)
@Override
public void run() (
// TODO Auto-generated method stub
synchronized(this) (
this.increment();
System.out.println("Current thread being executed "
+ Thread.currentThread().getName() + " Current Thread value " + this.getMyVar());
)
)
)

Kod za klasu RaceCondition ostaje isti. Sada kod pokretanja koda, izlaz je sljedeći:

Output1:

Aktualni navoj koji se izvodi nit 1 Trenutna vrijednost navoja 1

Trenutni konac koji se izvodi nit 2 Trenutna vrijednost navoja 2

Trenutni konac koji se izvodi nit 3 Trenutna vrijednost navoja 3

Output2:

Aktualni navoj koji se izvodi nit 1 Trenutna vrijednost navoja 1

Trenutni konac koji se izvodi nit 3 Trenutna vrijednost navoja 2

Trenutni konac koji se izvodi nit 2 Trenutna vrijednost navoja 3

Primijetite da naš kôd daje očekivani izlaz. Ovdje svaka nit povećava vrijednost za 1 za varijablu "myVar" (u klasi "Modify").

Napomena: Sinhronizacija je potrebna kada na istom objektu djeluje više niti. Ako na više objekata djeluje više niti, tada nije potrebna sinkronizacija.

Na primjer, modificirajte kôd u klasi „RaceCondition“ na sljedeći način i radimo s prethodno nesinhroniziranom klasom „Modify“.

package JavaConcepts;
public class RaceCondition (
public static void main(String() args) (
Modify mObj = new Modify();
Modify mObj1 = new Modify();
Modify mObj2 = new Modify();
Thread t1 = new Thread(mObj, "thread 1");
Thread t2 = new Thread(mObj1, "thread 2");
Thread t3 = new Thread(mObj2, "thread 3");
t1.start();
t2.start();
t3.start();
)
)

Izlaz:

Aktualni navoj koji se izvodi nit 1 Trenutna vrijednost navoja 1

Trenutni konac koji se izvodi nit 2 Trenutna vrijednost navoja 1

Trenutni konac koji se izvodi nit 3 Trenutna vrijednost navoja 1

Vrste sinkronizacije u Javi:

Postoje dvije vrste nitnih sinkronizacija, jedna međusobno isključiva, a druga međusobna komunikacija.

1.Uzajamno isključivi

  • Sinkronizirana metoda.
  • Statička sinkronizirana metoda
  • Sinkronizirani blok.

2. Koordinacija teme (komunikacija između niti u javi)

Uzajamno isključivi:

  • U ovom slučaju, niti dobivaju zaključavanje prije rada na objektu, izbjegavajući tako da rade s objektima za koje su njihove vrijednosti manipulirale drugim nitima.
  • To se može postići na tri načina:

ja. Sinkronizirana metoda: Možemo iskoristiti "sinkroniziranu" ključnu riječ za metodu, čineći je sinkroniziranom metodom. Svaka nit koja poziva sinhroniziranu metodu dobit će bravu za taj objekt i otpustiti je nakon završetka operacije. U gornjem primjeru, naša metoda "run ()" može se učiniti sinkroniziranom pomoću ključne riječi "sinkronizirano" nakon modifikatora pristupa.

@Override
public synchronized void run() (
// TODO Auto-generated method stub
this.increment();
System.out.println("Current thread being executed "
+ Thread.currentThread().getName() + " Current Thread value " + this.getMyVar());
)

Izlaz za ovaj slučaj će biti:

Aktualni navoj koji se izvodi nit 1 Trenutna vrijednost navoja 1

Trenutni konac koji se izvodi nit 3 Trenutna vrijednost navoja 2

Trenutni konac koji se izvodi nit 2 Trenutna vrijednost navoja 3

ii. Statička sinkronizirana metoda: Za sinkronizaciju statičkih metoda potrebno je steći zaključavanje na razini klase. Nakon što nit dobije zaključavanje razine klase samo tada će moći izvršiti statičku metodu. Iako nit drži zaključavanje razine klase, niti jedan drugi nit ne može izvršiti nijednu drugu statičku sinkronizacijsku metodu te klase. Međutim, ostale niti mogu izvesti bilo koju drugu redovitu metodu ili redovitu statičku metodu ili čak nestalnu sinhroniziranu metodu te klase.

Na primjer, razmotrimo našu klasu "Modify" (Promijeni) i u nju napravimo promjene pretvaranjem naše metode "prirasta" u statičku sinkronu metodu. Izmjene koda su kako slijedi:

package JavaConcepts;
public class Modify implements Runnable(
private static int myVar=0;
public int getMyVar() (
return myVar;
)
public void setMyVar(int myVar) (
this.myVar = myVar;
)
public static synchronized void increment() (
myVar++;
System.out.println("Current thread being executed " + Thread.currentThread().getName() + " Current Thread value " + myVar);
)
@Override
public void run() (
// TODO Auto-generated method stub
increment();
)
)

iii. Sinkronizirani blok: Jedan od glavnih nedostataka sinkronizirane metode jest taj što povećava vrijeme čekanja niti utječe na performanse koda. Stoga, da biste mogli sinkronizirati samo tražene retke koda umjesto cijele metode, potrebno je koristiti sinkronizirani blok. Korištenje sinkroniziranog bloka smanjuje vrijeme čekanja niti i također poboljšava performanse. U prethodnom primjeru već smo koristili sinkronizirani blok dok smo prvi put sinkronizirali svoj kod.

Primjer:
public void run() (
// TODO Auto-generated method stub
synchronized(this) (
this.increment();
System.out.println("Current thread being executed "
+ Thread.currentThread().getName() + " Current Thread value " + this.getMyVar());
)
)

Koordinacija navoja:

Za sinkronizirane niti komunikacija između niti je važan zadatak. Ugrađene metode koje pomažu u međusobnoj komunikaciji za sinkronizirani kôd su:

  • čekati()
  • obavijestiti()
  • notifyAll ()

Napomena: Ove metode pripadaju objektnoj klasi, a ne klasi niti. Da bi nit mogla pozivati ​​ove metode na objekt, trebalo bi ga držati bravu na tom objektu. Također, ove metode uzrokuju da nit oslobodi zaključavanje na objektu na koji se poziva.

wait (): nit kod pozivanja metode wait (), oslobađa zaključavanje objekta i prelazi u stanje čekanja. Ima dvije metode preopterećenja:

  • javno finalno void wait () baca InterruptedException
  • javno konačno neispravno čekanje (dugotrajno isteklo) izbacuje InterruptedException
  • javno završno void čekanje (long timeout, int nanos) izbacuje InterruptedException

notify (): nit šalje signal drugoj niti u stanju čekanja koristeći metodu notify (). Obavijest šalje samo jednoj niti da bi ta nit mogla nastaviti svoje izvršavanje. Koji će niz primiti obavijest među svim nitima u stanju čekanja ovisi o Java virtualnom stroju.

  • javna konačna nevaljana obavijest ()

notifyAll (): Kada nit poziva metod notifyAll (), obavijesti se svaka nit u stanju čekanja. Ove će se teme izvršavati jedna za drugom na temelju redoslijeda koji je odredio Java Virtual Machine.

  • javno konačno nevaljano obaveštenjeAll ()

Zaključak

U ovom smo članku vidjeli kako rad u okruženju s više niti može dovesti do neusklađenosti podataka zbog utrke. Kako nam sinkronizacija pomaže da to prevladamo tako što ograničavamo jednu nit da djeluje na zajedničkom resursu u isto vrijeme. Također i kako sinkronizirane niti međusobno komuniciraju.

Preporučeni članci:

Ovo je vodič za Što je sinkronizacija u Javi ?. Ovdje razgovaramo o uvođenju, razumijevanju, potrebi, radu i vrstama sinkronizacije s nekim uzorkom koda. Možete i proći naše druge predložene članke da biste saznali više -

  1. Serijalizacija u Javi
  2. Što je generika u Javi?
  3. Što je API na Javi?
  4. Što je binarno stablo na Javi?
  5. Primjeri i način na koji generički djeluju u C #

Kategorija: