CodeGym /Java blogg /Slumpmässig /Trådsynkronisering. Den synkroniserade operatören
John Squirrels
Nivå
San Francisco

Trådsynkronisering. Den synkroniserade operatören

Publicerad i gruppen
Hej! Idag kommer vi att fortsätta att överväga funktionerna i flertrådsprogrammering och prata om trådsynkronisering. Trådsynkronisering.  Den synkroniserade operatören - 1

Vad är synkronisering i Java?

Utanför programmeringsdomänen innebär det ett arrangemang som tillåter två enheter eller program att arbeta tillsammans. Till exempel kan en smartphone och dator synkroniseras med ett Google-konto, och ett webbplatskonto kan synkroniseras med sociala nätverkskonton så att du kan använda dem för att logga in. Trådsynkronisering har en liknande innebörd: det är ett arrangemang där trådar interagerar med varandra. I tidigare lektioner har våra trådar levt och fungerat separat från varandra. En gjorde en beräkning, en andra sov och en tredje visade något på konsolen, men de interagerade inte. I riktiga program är sådana situationer sällsynta. Flera trådar kan aktivt arbeta med och modifiera samma datamängd. Detta skapar problem. Föreställ dig att flera trådar skriver text till samma plats, till exempel till en textfil eller konsolen. I det här fallet blir filen eller konsolen en delad resurs. Trådarna är omedvetna om varandras existens, så de skriver helt enkelt allt de kan på den tid som tilldelats dem av trådschemaläggaren. I en ny lektion såg vi ett exempel på vart detta leder. Låt oss komma ihåg det nu: Trådsynkronisering.  Den synkroniserade operatören - 2Anledningen ligger i det faktum att trådarna arbetar med en delad resurs (konsolen) utan att koordinera sina handlingar med varandra. Om trådschemaläggaren allokerar tid till Thread-1, skriver den omedelbart allt till konsolen. Vilka andra trådar som har eller inte redan har lyckats skriva spelar ingen roll. Resultatet är, som du kan se, deprimerande. Det är därför de introducerade ett speciellt koncept, mutex (ömsesidig uteslutning), för flertrådsprogrammering. Syftet med en mutexär att tillhandahålla en mekanism så att endast en tråd har tillgång till ett objekt vid en viss tidpunkt. Om Tråd-1 förvärvar objekt A:s mutex, kommer de andra trådarna inte att kunna komma åt och ändra objektet. De andra trådarna måste vänta tills objekt A:s mutex släpps. Här är ett exempel från livet: föreställ dig att du och 10 andra främlingar deltar i en övning. Man måste turas om att uttrycka sina idéer och diskutera något. Men eftersom ni ser varandra för första gången, för att inte ständigt avbryta varandra och bli rasande, använder ni en "talande boll": bara personen med bollen kan tala. På så sätt får du en bra och givande diskussion. I grund och botten är bollen en mutex. Om ett objekts mutex är i händerna på en tråd kan andra trådar inte fungera med objektet.Objectklass, vilket innebär att varje objekt i Java har en.

Hur den synkroniserade operatören fungerar

Låt oss lära känna ett nytt nyckelord: synkroniserat . Den används för att markera ett visst kodblock. Om ett kodblock är markerat med nyckelordet synchronizedkan det blocket endast exekveras av en tråd åt gången. Synkronisering kan implementeras på olika sätt. Till exempel, genom att förklara att en hel metod ska synkroniseras:

public synchronized void doSomething() {

   // ...Method logic
}
Eller skriv ett kodblock där synkronisering utförs med något objekt:

public class Main {

   private Object obj = new Object();

   public void doSomething() {

       // ...Some logic available simultaneously to all threads

       synchronized (obj) {

           // Logic available to just one thread at a time
       }
   }
}
Innebörden är enkel. Om en tråd går in i kodblocket märkt med synchronizednyckelordet, fångar den omedelbart objektets mutex, och alla andra trådar som försöker komma in i samma block eller metod tvingas vänta tills den föregående tråden slutför sitt arbete och släpper monitorn. Trådsynkronisering.  Den synkroniserade operatören - 3Förresten! Under kursen har du redan sett exempel på , synchronizedmen de såg annorlunda ut:

public void swap()
{
   synchronized (this)
   {
       // ...Method logic
   }
}
Ämnet är nytt för dig. Och, naturligtvis, kommer det att finnas förvirring med syntaxen. Så, memorera det direkt för att undvika att bli förvirrad senare av de olika sätten att skriva det. Dessa två sätt att skriva det betyder samma sak:

public void swap() {

   synchronized (this)
   {
       // ...Method logic
   }
}


public synchronized void swap() {

   }
}
I det första fallet skapar du ett synkroniserat kodblock direkt när du anger metoden. Det synkroniseras av thisobjektet, dvs det aktuella objektet. Och i det andra exemplet tillämpar du synchronizednyckelordet på hela metoden. Detta gör det onödigt att explicit ange objektet som används för synkronisering. Eftersom hela metoden är markerad med nyckelordet kommer metoden automatiskt att synkroniseras för alla instanser av klassen. Vi kommer inte att fördjupa oss i en diskussion om vilken väg som är bättre. För nu, välj vilket sätt du gillar bäst :) Det viktigaste är att komma ihåg: du kan bara förklara en metod synkroniserad när all dess logik exekveras av en tråd i taget. Det skulle till exempel vara ett misstag att göra följande doSomething()metod synkroniserad:

public class Main {

   private Object obj = new Object();

   public void doSomething() {

       // ...Some logic available simultaneously to all threads

       synchronized (obj) {

           // Logic available to just one thread at a time
       }
   }
}
Som du kan se innehåller en del av metoden logik som inte kräver synkronisering. Den koden kan köras av flera trådar samtidigt, och alla kritiska platser är åtskilda i ett separat synchronizedblock. Och en sak till. Låt oss noggrant undersöka vårt exempel från lektionen med namnbyte:

public void swap()
{
   synchronized (this)
   {
       // ...Method logic
   }
}
Obs: synkronisering utförs medthis. Det vill säga att använda ett specifiktMyClassobjekt. Anta att vi har 2 trådar (Thread-1ochThread-2) och bara ettMyClass myClassobjekt. I det här fallet, omThread-1anropasmyClass.swap(), kommer objektets mutex att vara upptagen, och när man försöker anropamyClass.swap()metodenThread-2att hänga sig medan man väntar på att mutexet ska släppas. Om vi ​​kommer att ha 2 trådar och 2MyClassobjekt (myClass1ochmyClass2), kan våra trådar enkelt köra de synkroniserade metoderna på olika objekt samtidigt. Den första tråden kör detta:

myClass1.swap();
Den andra utför detta:

myClass2.swap();
I det här fallet kommer synchronizednyckelordet i swap()metoden inte att påverka programmets funktion, eftersom synkronisering utförs med ett specifikt objekt. Och i det senare fallet har vi 2 objekt. Trådarna skapar alltså inga problem för varandra. När allt kommer omkring har två objekt 2 olika mutexer, och att förvärva den ena är oberoende av att förvärva den andra .

Specialfunktioner för synkronisering i statiska metoder

Men vad händer om du behöver synkronisera en statisk metod ?

class MyClass {
   private static String name1 = "Ally";
   private static String name2 = "Lena";

   public static synchronized void swap() {
       String s = name1;
       name1 = name2;
       name2 = s;
   }

}
Det är inte klart vilken roll mutexen kommer att spela här. När allt kommer omkring har vi redan bestämt att varje objekt har en mutex. Men problemet är att vi inte behöver objekt för att anropa metoden MyClass.swap(): metoden är statisk! Så vad händer härnäst? :/ Det är faktiskt inga problem här. Javas skapare tog hand om allt :) Om en metod som innehåller kritisk samtidig logik är statisk, så utförs synkronisering på klassnivå. För större tydlighet kan vi skriva om ovanstående kod enligt följande:

class MyClass {
   private static String name1 = "Ally";
   private static String name2 = "Lena";

   public static void swap() {

       synchronized (MyClass.class) {
           String s = name1;
           name1 = name2;
           name2 = s;
       }
   }

}
I princip kunde du ha tänkt på det här själv: Eftersom det inte finns några objekt måste synkroniseringsmekanismen på något sätt vara inbakad i själva klassen. Och det är så det är: vi kan använda klasser för att synkronisera.
Kommentarer
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION