Introduktion til synkronisering i Java

Synkronisering er en Java-funktion, der begrænser flere tråde fra at forsøge at få adgang til de ofte delte ressourcer på samme tid. Her refererede delte ressourcer til ekstern filindhold, klassevariabler eller databaseposter.

Synkronisering er vidt brugt i multithread-programmering. "Synkroniseret" er det nøgleord, der giver din kode muligheden for kun at tillade en enkelt tråd at operere på den uden interferens fra nogen anden tråd i denne periode.

Hvorfor har vi brug for synkronisering i Java?

  • Java er et multitrådigt programmeringssprog. Dette betyder, at to eller flere tråde kan køre samtidigt mod afslutningen af ​​en opgave. Når tråde kører samtidig, er der store chancer for, at der opstår et scenarie, hvor din kode muligvis giver uventede resultater.
  • Du kan undre dig over, at hvis multithreading kan forårsage fejlagtige output, hvorfor betragtes det som en vigtig funktion i Java?
  • Multithreading gør din kode hurtigere ved at køre flere tråde parallelt og dermed reducere udførelsestiden for dine koder og give høj ydelse. Imidlertid fører anvendelse af multitrådemiljøet til unøjagtige output på grund af en tilstand, der almindeligvis er kendt som en race-tilstand.

Hvad er en racetilstand?

Når to eller flere tråde løber parallelt, har de en tendens til at få adgang til og ændre delte ressourcer på det tidspunkt. Sekvenserne, i hvilke trådene udføres, bestemmes af trådplanlægningsalgoritmen.

På grund af dette kan man ikke forudsige den rækkefølge, i hvilken tråde udføres, da de kun styres af trådplanlæggeren. Dette påvirker output af koden og resulterer i inkonsekvente output. Da flere tråde kører med hinanden for at afslutte operationen, betegnes betingelsen ”racingtilstand”.

Lad os f.eks. Overveje nedenstående kode:

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

Ved fortløbende kørsel af ovenstående kode vil output være som følger:

Ourput1:

Aktuel tråd, der udføres tråd 1 Aktuel trådværdi 3

Aktuel tråd, der udføres tråd 3 Aktuel trådværdi 2

Aktuel tråd, der udføres tråd 2 Aktuel trådværdi 3

Output2:

Aktuel tråd, der udføres tråd 3 Aktuel trådværdi 3

Aktuel tråd, der udføres tråd 2 Aktuel trådværdi 3

Aktuel tråd, der udføres tråd 1 Aktuel trådværdi 3

Output3:

Aktuel tråd, der udføres tråd 2 Aktuel trådværdi 3

Aktuel tråd, der udføres tråd 1 Aktuel trådværdi 3

Aktuel tråd, der udføres tråd 3 Aktuel trådværdi 3

udgang4:

Aktuel tråd, der udføres tråd 1 Aktuel trådværdi 2

Aktuel tråd, der udføres tråd 3 Aktuel trådværdi 3

Aktuel tråd, der udføres tråd 2 Aktuel trådværdi 2

  • Fra ovenstående eksempel kan du konkludere, at trådene udføres tilfældigt, og at værdien også er forkert. I henhold til vores logik skal værdien øges med 1. Men her er outputværdien i de fleste tilfælde 3 og i nogle få tilfælde er den 2.
  • Her er "myVar" -variablen den delte ressource, som flere tråde udfører på. Trådene får adgang til og ændrer værdien af ​​"myVar" samtidig. Lad os se, hvad der sker, hvis vi kommenterer de to andre tråde.

Outputet i dette tilfælde er:

Den aktuelle tråd, der udføres tråd 1 Aktuel trådværdi 1

Dette betyder, at når en enkelt tråd kører, er output som forventet. Når flere tråde kører, ændres værdien dog af hver tråd. Derfor skal man begrænse antallet af tråde, der arbejder på en delt ressource, til en enkelt tråd ad gangen. Dette opnås ved hjælp af synkronisering.

Forstå, hvad der er synkronisering i Java

  • Synkronisering i Java opnås ved hjælp af nøgleordet "synkroniseret". Dette nøgleord kan bruges til metoder eller blokke eller objekter, men kan ikke bruges med klasser og variabler. Et synkroniseret stykke kode tillader kun en tråd at få adgang til og ændre den på et givet tidspunkt.
  • Imidlertid påvirker et synkroniseret stykke kode kodeydelsen, da det øger ventetiden for andre tråde, der prøver at få adgang til den. Så et kodestykke skal kun synkroniseres, når der er en chance for, at en racetilstand opstår. Hvis ikke, skal man undgå det.

Hvordan fungerer synkronisering i Java internt?

  • Intern synkronisering i Java er implementeret ved hjælp af låsekoncept (også kendt som en monitor). Hvert Java-objekt har sin egen lås. I en synkroniseret kodeblok skal en tråd tilegne sig låsen, inden han er i stand til at udføre den bestemte blok af kode. Når en tråd erhverver låsen, kan den udføre det stykke kode.
  • Når færdiggørelsen er afsluttet, frigøres den automatisk låsen. Hvis en anden tråd kræver at arbejde på den synkroniserede kode, venter den på, at den aktuelle tråd, der fungerer på den, frigør låsen. Denne proces med at erhverve og frigive låse er internt taget hånd om af den virtuelle Java-maskine. Et program er ikke ansvarligt for at erhverve og frigive låse ved hjælp af tråden. De resterende tråde kan imidlertid udføre ethvert andet ikke-synkroniseret stykke kode samtidig.

Lad os synkronisere vores tidligere eksempel ved at synkronisere koden inden for køremetoden ved hjælp af den synkroniserede blok i klassen “Ændre” som nedenfor:

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

Koden for klassen “RaceCondition” forbliver den samme. Når koden nu køres, er output som følger:

Output1:

Den aktuelle tråd, der udføres tråd 1 Aktuel trådværdi 1

Den aktuelle tråd, der udføres, tråd 2 Aktuel trådværdi 2

Den aktuelle tråd, der udføres, tråd 3 Aktuel trådværdi 3

Output2:

Den aktuelle tråd, der udføres tråd 1 Aktuel trådværdi 1

Den aktuelle tråd, der udføres, tråd 3 Aktuel trådværdi 2

Den aktuelle tråd, der udføres, tråd 2 Aktuel trådværdi 3

Bemærk, at vores kode leverer den forventede output. Her øger hver tråd værdien med 1 for variablen “myVar” (i klassen “Modificer”).

Bemærk: Synkronisering er påkrævet, når flere tråde fungerer på det samme objekt. Hvis flere tråde fungerer på flere objekter, er synkronisering ikke påkrævet.

Lad os for eksempel ændre koden i klassen “RaceCondition” som nedenfor og arbejde med den tidligere ikke synkroniserede klasse “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();
)
)

Produktion:

Den aktuelle tråd, der udføres tråd 1 Aktuel trådværdi 1

Den aktuelle tråd, der udføres, tråd 2 Aktuel trådværdi 1

Den aktuelle tråd, der udføres, tråd 3 Aktuel trådværdi 1

Typer af synkronisering i Java:

Der er to typer trådsynkronisering, den ene er gensidigt eksklusiv og den anden kommunikation mellem trådene.

1.Mutually Exclusive

  • Synkroniseret metode.
  • Statisk synkroniseret metode
  • Synkroniseret blok.

2. Trådkoordination (inter-tråd kommunikation i java)

Gensidigt eksklusivt:

  • I dette tilfælde får tråde låsen, før de arbejder på et objekt, hvorved man undgår at arbejde med objekter, der har fået deres værdier manipuleret med andre tråde.
  • Dette kan opnås på tre måder:

jeg. Synkroniseret metode: Vi kan bruge det "synkroniserede" nøgleord til en metode og dermed gøre det til en synkroniseret metode. Hver tråd, der påberåber sig den synkroniserede metode, får låsen til dette objekt og frigiver den, når dens operation er afsluttet. I ovenstående eksempel kan vi gøre vores “run ()” -metode som synkroniseret ved hjælp af det “synkroniserede” nøgleord efter adgangsmodifikatoren.

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

Outputet til dette tilfælde vil være:

Den aktuelle tråd, der udføres tråd 1 Aktuel trådværdi 1

Den aktuelle tråd, der udføres, tråd 3 Aktuel trådværdi 2

Den aktuelle tråd, der udføres, tråd 2 Aktuel trådværdi 3

ii. Statisk synkroniseret metode: For at synkronisere statiske metoder er man nødt til at erhverve sin klassens lås. Når en tråd kun får klasseniveauet, vil den kunne udføre en statisk metode. Mens en tråd har klassens lås, kan ingen anden tråd udføre nogen anden statisk synkroniseret metode i den klasse. Imidlertid kan de andre tråde udføre enhver anden regelmæssig metode eller almindelig statisk metode eller endda ikke-statisk synkroniseret metode i den klasse.

Lad os f.eks. Overveje vores klasse "Modificer" og foretage ændringer i den ved at konvertere vores "inkrement" -metode til en statisk synkroniseret metode. Koden ændringer er som nedenfor:

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. Synkroniseret blok: En af de største ulemper ved den synkroniserede metode er, at den øger trådens ventetid, der påvirker kodens ydelse. Derfor er der kun brug for en synkroniseret blok for at være i stand til kun at synkronisere de krævede kodelinjer i stedet for hele metoden. Brug af synkroniseret blok reducerer trådens ventetid og forbedrer også ydeevnen. I det foregående eksempel har vi allerede gjort brug af en synkroniseret blok, mens vi synkroniserer vores kode for første gang.

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

Trådkoordinering:

For synkroniserede tråde er kommunikation mellem trådene en vigtig opgave. Indbyggede metoder, der hjælper med at opnå inter-tråd kommunikation til synkroniseret kode, er:

  • vente()
  • underrette()
  • notifyAll ()

Bemærk: Disse metoder hører til objektklassen og ikke trådklassen. For at en tråd skal kunne påkalde disse metoder på et objekt, skal den holde låsen på dette objekt. Disse fremgangsmåder får også en tråd til at frigøre sin lås på det objekt, som det påberopes.

vent (): En tråd ved påkaldende vent () -metode, frigiver låsen på objektet og går i ventetilstand. Det har to metodeoverbelastninger:

  • public final void wait () kaster InterruptException
  • offentlig endelig ugyldig ventetid (lang timeout) kaster InterruptException
  • offentlig endelig ugyldig ventetid (lang timeout, int nanos) kaster InterruptException

notify (): En tråd sender et signal til en anden thread i ventetilstand ved at bruge metoden (notify). Den sender underretningen til kun en tråd, således at denne tråd kan genoptage udførelsen. Hvilken tråd der modtager underretningen blandt alle trådene i ventetilstand afhænger af Java Virtual Machine.

  • offentlig endelig ugyldig meddelelse ()

notifyAll (): Når en tråd påberåber notifyAll () -metoden, meddeles hver tråd i dens ventetilstand. Disse tråde udføres den ene efter den anden baseret på den ordre, der er besluttet af Java Virtual Machine.

  • offentlig endelig ugyldig meddelelseAlle ()

Konklusion

I denne artikel har vi set, hvordan arbejde i et flertrådet miljø kan føre til datakonsistens på grund af en race-tilstand. Hvordan synkronisering hjælper os med at overvinde dette ved at begrænse en enkelt tråd til at fungere på en delt ressource ad gangen. Også hvordan synkroniserede tråde kommunikerer med hinanden.

Anbefalede artikler:

Dette har været en guide til Hvad er synkronisering i Java ?. Her diskuterer vi introduktion, forståelse, behov, arbejde og typer af synkronisering med en bestemt prøvekode. Du kan også gennemgå vores andre foreslåede artikler for at lære mere -

  1. Serialisering i Java
  2. Hvad er Generics i Java?
  3. Hvad er API i Java?
  4. Hvad er et binært træ i Java?
  5. Eksempler og hvordan generics fungerer i C #

Kategori: