Sissejuhatus Java sünkroonimisse

Sünkroonimine on Java-funktsioon, mis takistab mitmetel lõimedel ühiselt ühiskasutatavatele ressurssidele korraga juurde pääseda. Jagatud ressursid viitavad siin välisele failisisule, klassimuutujatele või andmebaasi kirjetele.

Sünkroonimist kasutatakse laialdaselt mitme keermega programmeerimisel. „Sünkroniseeritud” on märksõna, mis annab teie koodile võimaluse lubada sellel töötada ainult ühel lõimel ilma ühegi teise lõime segamiseta sel perioodil.

Miks me vajame Java sünkroonimist?

  • Java on mitme keermega programmeerimiskeel. See tähendab, et kaks või enam lõime võivad samaaegselt kulgeda ülesande täitmise suunas. Kui lõimed töötavad samaaegselt, on suur tõenäosus stsenaariumi tekkeks, kus teie kood võib pakkuda ootamatuid tulemusi.
  • Võite küsida, et kui mitmekordne lõng võib põhjustada ekslikke väljundeid, miks peetakse seda Java oluliseks funktsiooniks?
  • Mitmekeermestamine muudab teie koodi kiiremaks, käivitades mitu lõime paralleelselt, vähendades sellega koodide täitmise aega ja pakkudes kõrget jõudlust. Mitmekeermelise keskkonna kasutamine toob aga kaasa ebatäpseid väljundeid, mis on tingitud seisundist, mida tavaliselt nimetatakse rassitingimuseks.

Mis on võistlustingimused?

Kui kaks või enam lõime töötab paralleelselt, kipuvad nad sellel ajahetkel ühiskasutatavatele ressurssidele juurde pääsema ja neid muutma. Järjestused, milles lõime täidetakse, otsustatakse lõimede ajastamise algoritmi abil.

Seetõttu ei saa ennustada lõimede täitmise järjekorda, kuna seda kontrollib ainult lõimede planeerija. See mõjutab koodi väljundit ja tulemuseks on ebajärjekindel väljund. Kuna operatsiooni lõpuleviimiseks võistlevad omavahel mitu keermet, nimetatakse seda tingimust “võidusõidutingimuseks”.

Vaatleme näiteks järgmist koodi:

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();
)
)

Ülaltoodud koodi järjestikulisel käivitamisel on väljundid järgmised:

Meie sisend1:

Praegune lõim täidetakse lõim 1 Praegune lõime väärtus 3

Praegune lõim täidetakse lõime 3 Praegune lõime väärtus 2

Praegune lõim täidetakse keermes 2 Praegune lõime väärtus 3

2. väljund:

Praegune lõim täidetakse lõime 3 Praegune lõime väärtus 3

Praegune lõim täidetakse keermes 2 Praegune lõime väärtus 3

Praegune lõim täidetakse lõim 1 Praegune lõime väärtus 3

Väljund3:

Praegune lõim täidetakse keermes 2 Praegune lõime väärtus 3

Praegune lõim täidetakse lõim 1 Praegune lõime väärtus 3

Praegune lõim täidetakse lõime 3 Praegune lõime väärtus 3

Väljund4:

Praegune lõim täidetakse lõim 1 Praegune lõime väärtus 2

Praegune lõim täidetakse lõime 3 Praegune lõime väärtus 3

Praegune lõim täidetakse lõime 2 Praegune lõime väärtus 2

  • Ülaltoodud näite põhjal saate järeldada, et lõime täidetakse juhuslikult ja ka väärtus on vale. Meie loogika kohaselt tuleks väärtust suurendada ühega. Kuid siin on väljundväärtus enamasti 3 ja mõnel juhul 2.
  • Siin on muutuja “myVar” jagatud ressurss, millel mitu lõime käivitatakse. Nimed saavad juurdepääsu ja muudavad “myVar” väärtust üheaegselt. Vaatame, mis juhtub, kui kommenteerime ülejäänud kahte lõime.

Sel juhul on väljund:

Praegune lõimitav lõim 1 lõng Praegune lõime väärtus 1

See tähendab, et ühe lõime töötamisel on väljund ootuspärane. Kui töötab mitu lõime, muudab iga niit väärtust. Seetõttu peab jagatud ressursil töötavate lõimede arv olema piiratud ühe lõimega korraga. See saavutatakse sünkroonimise abil.

Mis on Java sünkroonimine?

  • Sünkroonimine Java-s saavutatakse märksõna „sünkroniseeritud” abil. Seda märksõna saab kasutada meetodite, plokkide või objektide jaoks, kuid seda ei saa kasutada klasside ja muutujatega. Sünkroonitud kooditükk võimaldab sellel kellaajal konkreetsel ajal juurde pääseda ja seda muuta.
  • Sünkroonitud kooditükk mõjutab siiski koodi jõudlust, kuna see suurendab teiste sellele juurdepääsu võimaldavate lõimede ooteaega. Seega tuleks kooditükki sünkroniseerida ainult siis, kui on olemas võistlusolukorra tekkimise võimalus. Kui mitte, siis tuleks seda vältida.

Kuidas Java sünkroonimine sisemiselt toimib?

  • Java sisemine sünkroonimine on rakendatud luku (tuntud ka kui monitori) abil. Igal Java-objektil on oma lukk. Sünkroonitud koodiplokis peab niit enne selle konkreetse koodiploki täitmist luku omandama. Kui niit lukustuse omandab, saab see selle koodi käivitada.
  • Täitmise lõppedes vabastab see luku automaatselt. Kui sünkroonitud koodiga töötamiseks on vaja mõnda muud lõime, ootab see sellel töötavat lõime luku vabastamist. Selle lukkude hankimise ja vabastamise protsessi eest hoolitseb sisemiselt Java virtuaalmasin. Programm ei vastuta lukkude omandamise ja vabastamise eest niidi abil. Ülejäänud lõimed võivad aga samaaegselt käivitada ka muid sünkroniseerimata kooditükke.

Sünkroonige meie eelmine näide, sünkroniseerides käitamismeetodi koodi, kasutades sünkroonitud plokki klassis „Muuda” nagu allpool:

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());
)
)
)

Klassi RaceCondition kood jääb samaks. Koodi käitamisel on väljund järgmine:

Väljund1:

Praegune lõimitav lõim 1 lõng Praegune lõime väärtus 1

Praegune lõimitud lõim 2 - niit Praegune lõime väärtus 2

Käimasolev keermestatav lõim 3 Praegune lõime väärtus 3

2. väljund:

Praegune lõimitav lõim 1 lõng Praegune lõime väärtus 1

Praegune lõimitav lõim 3 - niidi praegune väärtus 2

Praegu käimasolev lõim 2 - niit Praegune lõime väärtus 3

Pange tähele, et meie kood pakub oodatud väljundit. Siin suurendab iga niit muutuja “myVar” (klassis “Muuda”) väärtust ühe võrra.

Märkus. Kui samal objektil töötab mitu lõime, on vajalik sünkroonimine. Kui mitu lõime töötab mitmel objektil, pole sünkroonimine vajalik.

Näiteks muutkem klassis „RaceCondition” olevat koodi nagu allpool ja töötage varem sünkroniseerimata klassiga „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();
)
)

Väljund:

Praegune lõimitav lõim 1 lõng Praegune lõime väärtus 1

Praegune lõimitav lõim 2 - niit Praegune lõime väärtus 1

Praegune lõimitav lõim 3 - niidi praegune väärtus 1

Java sünkroonimise tüübid:

Lõimede sünkroonimistüüpe on kahte tüüpi: üks on üksteist välistav ja teine ​​lõimedevaheline.

1.Metselt välistav

  • Sünkroniseeritud meetod.
  • Staatiline sünkroniseeritud meetod
  • Sünkroniseeritud plokk.

2.Lõimede koordineerimine (lõimedevaheline suhtlus javas)

Üksteist välistavad:

  • Sel juhul saavad niidid lukustuse enne objektil töötamist, vältides sellega tööd objektidega, mille väärtusi on muude niididega manipuleeritud.
  • Seda saab saavutada kolmel viisil:

i. Sünkroonitud meetod: saame meetodi jaoks kasutada märksõna „sünkroniseeritud”, muutes selle sünkroniseeritud meetodiks. Iga lõim, mis kutsub esile sünkroonitud meetodi, hangib selle objekti luku ja vabastab selle, kui see on lõpule viidud. Ülaltoodud näites saame oma "run ()" meetodi sünkroniseerida, kasutades pöördusmuunduri järel märksõna "sünkroniseeritud".

@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());
)

Selle juhtumi väljund on:

Praegune lõimitav lõim 1 lõng Praegune lõime väärtus 1

Praegune lõimitav lõim 3 - niidi praegune väärtus 2

Praegu käimasolev lõim 2 - niit Praegune lõime väärtus 3

ii. Staatiline sünkroniseeritud meetod: staatiliste meetodite sünkroonimiseks tuleb omandada selle klassi lukk. Pärast seda, kui lõim saab klassitaseme lukustuse alles siis on see võimeline teostama staatilist meetodit. Ehkki lõim hoiab klassi tasemel lukku, ei saa ükski teine ​​lõim käivitada ühtegi muud selle klassi staatilist sünkroniseeritud meetodit. Teised lõimed võivad siiski käivitada selle klassi mis tahes muud tavalist meetodit või tavalist staatilist meetodit või isegi mittestaatilist sünkroniseeritud meetodit.

Mõelgem näiteks oma klassile „Modify“ ja teeme selles muudatusi, teisendades „juurdekasvu“ meetodi staatiliseks sünkroniseeritud meetodiks. Koodimuutused on järgmised:

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. Sünkroonitud plokk: sünkroniseeritud meetodi üks peamisi puudusi on see, et see suurendab keermete ooteaega, mõjutades koodi jõudlust. Seetõttu on kogu meetodi asemel vajalike koodiridade sünkroonimiseks vaja kasutada sünkroonitud plokki. Sünkroonitud ploki kasutamine vähendab lõimede ooteaega ja parandab ka jõudlust. Eelmises näites oleme oma koodi esmakordsel sünkroonimisel juba sünkroonitud plokki kasutanud.

Näide:
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());
)
)

Keerme koordineerimine:

Sünkroonitud niitide puhul on oluline ülesanne lõimedevaheline suhtlus. Sisseehitatud meetodid, mis aitavad saavutada sünkroniseeritud koodi keermesidet, on järgmised:

  • oota ()
  • teata ()
  • teavitada kõiki ()

Märkus. Need meetodid kuuluvad objektiklassi, mitte niidiklassi. Selleks, et niit saaks neid meetodeid objektile kutsuda, peaks see hoidma selle objekti lukku. Samuti põhjustavad need meetodid lõime oma luku vabastamiseks objektil, millele see kutsutakse.

wait (): lõime ootamismeetodi kutsumisest, vabastab objekti lukustuse ja läheb ooteolekusse. Sellel on kaks meetodi ülekoormust:

  • avalik lõplik tühine ootamine () viskab välja InterruptedException
  • avalik lõplik tühine ootamine (pikk aegumistähtaeg) loobub InterruptedException'ist
  • avalik lõplik tühine ootamine (pikk aegumine, int nanos) viskab InterruptedException

teavitada (): niit saadab signaali teisele lõimele ooteolekus, kasutades meetodit teavitada (). See saadab teatise ainult ühele lõimele, nii et see lõim saab selle täitmist jätkata. Milline lõim saab teate kõigi ooteolekus olevate lõimede vahel, sõltub Java virtuaalmasinast.

  • avalik lõplik tühine teatama ()

teavitadaAll (): kui lõim kutsub esile teateAll () meetodi, teatatakse igast ooteolekus olevast lõimast. Neid lõime täidetakse üksteise järel vastavalt Java virtuaalmasina otsusele.

  • avalik lõplik tühine teatisKõik ()

Järeldus

Selles artiklis nägime, kuidas mitme keermega keskkonnas töötamine võib võistlusolukorra tõttu põhjustada andmete ebajärjekindlust. Kuidas sünkroonimine aitab meil sellest üle saada, piirates ühe lõime toimimist korraga jagatud ressursil. Samuti see, kuidas sünkroniseeritud niidid omavahel suhelda saavad.

Soovitatavad artiklid:

See on olnud teemaks Mis on Java sünkroonimine ?. Siin käsitleme mõne näidiskoodiga sünkroonimise sissejuhatust, mõistmist, vajadust, toimimist ja sünkroonimise tüüpe. Lisateavet leiate ka meie muudest soovitatud artiklitest -

  1. Järjestus Java-s
  2. Mis on Java geneerika?
  3. Mis on Java Java?
  4. Mis on Java binaarne puu?
  5. Näited ja kuidas Generics töötab C #

Kategooria: