Java-trådlås og livelock

1. Oversigt

Mens multi-threading hjælper med at forbedre en applikations ydeevne, kommer det også med nogle problemer. I denne vejledning ser vi på to sådanne problemer, deadlock og livelock ved hjælp af Java-eksempler.

2. Deadlock

2.1. Hvad er deadlock?

En dødvande opstår, når to eller flere tråde venter for evigt på en lås eller ressource, som en anden af ​​tråde har. Derfor kan en applikation gå i stå eller mislykkes, da de fastlåste tråde ikke kan udvikle sig.

Det klassiske spisefilosofers problem demonstrerer pænt synkroniseringsproblemerne i et miljø med flere tråde og bruges ofte som et eksempel på dødvande.

2.2. Deadlock-eksempel

Lad os først se på et simpelt Java-eksempel for at forstå dødvande.

I dette eksempel opretter vi to tråde, T1 og T2. Tråd T1 opkald betjening1og tråd T2 opkald operationer.

Tråd for at afslutte deres operationer T1 har brug for at erhverve lås 1 først og derefter lås2, hvorimod tråd T2 har brug for at erhverve lås2 først og derefter lås 1. Så dybest set prøver begge tråde at erhverve låse i den modsatte rækkefølge.

Lad os nu skrive Deadlockeksempel klasse:

public class DeadlockExample {private Lock lock1 = new ReentrantLock (true); privat lås lås2 = ny ReentrantLock (sand); public static void main (String [] args) {DeadlockExample deadlock = new DeadlockExample (); ny tråd (deadlock :: operation1, "T1"). start (); ny tråd (deadlock :: operation2, "T2"). start (); } offentlig ugyldig handling1 () {lock1.lock (); print ("lock1 erhvervet, venter på at erhverve lock2."); søvn (50); lås2.lås (); print ("lock2 erhvervet"); print ("udførelse af første operation."); lock2.unlock (); lock1.unlock (); } offentlig ugyldig handling2 () {lock2.lock (); print ("lock2 erhvervet, venter på at erhverve lock1."); søvn (50); lås1.lås (); print ("lock1 erhvervet"); print ("udfører anden operation."); lock1.unlock (); lock2.unlock (); } // hjælpemetoder}

Lad os nu køre dette blokeringseksempel og bemærke output:

Tråd T1: lås1 erhvervet, venter på at skaffe lås2. Tråd T2: lås2 erhvervet, venter på at skaffe lås1.

Når vi har kørt programmet, kan vi se, at programmet resulterer i en blokering og aldrig afslutter. Loggen viser den tråd T1 venter på lås2, som holdes af tråden T2. Tråd ligeledes T2 venter på lås 1, som holdes af tråden T1.

2.3. Undgå deadlock

Deadlock er et almindeligt samtidighedsproblem i Java. Derfor skal vi designe en Java-applikation for at undgå eventuelle potentielle blokeringsforhold.

Til at begynde med bør vi undgå behovet for at erhverve flere låse til en tråd. Men hvis en tråd har brug for flere låse, skal vi sørge for, at hver tråd erhverver låsene i samme rækkefølge til undgå cyklisk afhængighed ved låseopsamling.

Vi kan også bruge tidsindstillede låseforsøg, ligesom tryLock metode i Låse interface for at sikre, at en tråd ikke blokeres uendeligt, hvis den ikke er i stand til at erhverve en lås.

3. Livelock

3.1. Hvad er livelock

Livelock er et andet samtidighedsproblem og svarer til dødvande. I husdyr, to eller flere tråde fortsætter med at overføre stater mellem hinanden i stedet for at vente uendeligt som vi så i dødvandseksemplet. Derfor er trådene ikke i stand til at udføre deres respektive opgaver.

Et godt eksempel på livelock er et messaging-system, hvor beskedforbrugeren, når en undtagelse opstår, ruller transaktionen tilbage og sætter beskeden tilbage til køens hoved. Derefter læses den samme besked gentagne gange fra køen, kun for at forårsage en anden undtagelse og sættes tilbage i køen. Forbrugeren vil aldrig hente nogen anden besked fra køen.

3.2. Livelock Eksempel

For at demonstrere den livlige tilstand tager vi det samme dødvandseksempel, som vi har diskuteret tidligere. I dette eksempel skal du også tråde T1 opkald betjening1 og tråd T2 opkald betjening2. Vi ændrer dog logikken i disse operationer lidt.

Begge tråde har brug for to låse for at fuldføre deres arbejde. Hver tråd får sin første lås, men finder ud af, at den anden lås ikke er tilgængelig. Så for at lade den anden tråd gennemføres først, frigiver hver tråd sin første lås og forsøger at erhverve begge låse igen.

Lad os demonstrere livelock med en Livelock Eksempel klasse:

offentlig klasse LivelockExample {private Lock lock1 = new ReentrantLock (true); privat lås lås2 = ny ReentrantLock (sand); public static void main (String [] args) {LivelockExample livelock = new LivelockExample (); ny tråd (livelock :: operation1, "T1"). start (); ny tråd (livelock :: operation2, "T2"). start (); } offentlig ugyldig handling1 () {while (true) {tryLock (lock1, 50); print ("lock1 erhvervet, forsøger at erhverve lock2."); søvn (50); hvis (tryLock (lock2)) {print ("lock2 erhvervet."); } andet {print ("kan ikke hente lås2, frigøre lås1."); lock1.unlock (); Blive ved; } print ("udførelse af første operation."); pause; } lås2.unlock (); lock1.unlock (); } offentlig ugyldig handling2 () {while (true) {tryLock (lock2, 50); print ("lock2 erhvervet, forsøger at erhverve lock1."); søvn (50); hvis (tryLock (lock1)) {print ("lock1 erhvervet."); } ellers {print ("kan ikke erhverve lås1, frigøre lås2."); lock2.unlock (); Blive ved; } print ("udfører anden handling."); pause; } lås1.unlock (); lock2.unlock (); } // hjælpemetoder}

Lad os nu køre dette eksempel:

Tråd T1: lås1 erhvervet, forsøger at skaffe lås2. Tråd T2: lås2 erhvervet, forsøger at skaffe lås1. Tråd T1: kan ikke hente lås2, frigøre lås1. Tråd T2: kan ikke hente lås1, frigøre lås2. Tråd T2: lås2 erhvervet, forsøger at skaffe lås1. Tråd T1: lås1 erhvervet, forsøger at skaffe lås2. Tråd T1: kan ikke hente lås2, frigøre lås1. Tråd T1: lås1 erhvervet, forsøger at skaffe lås2. Tråd T2: kan ikke hente lås1, frigøre lås2. ..

Som vi kan se i logfilerne, er begge tråde gentagne gange ved at erhverve og frigive låse. På grund af dette er ingen af ​​trådene i stand til at fuldføre operationen.

3.3. Undgå livelock

For at undgå en livelock er vi nødt til at undersøge den tilstand, der forårsager livelocken, og derefter finde en løsning i overensstemmelse hermed.

For eksempel, hvis vi har to tråde, der gentagne gange erhverver og frigiver låse, hvilket resulterer i livelock, kan vi designe koden, så trådene prøver igen at erhverve låse med tilfældige intervaller. Dette giver trådene en rimelig chance for at erhverve de låse, de har brug for.

En anden måde at tage sig af livsproblemet i det eksempel på messaging-systemet, vi har diskuteret tidligere, er at placere mislykkede meddelelser i en separat kø til videre behandling i stedet for at sætte dem tilbage i samme kø igen.

4. Konklusion

I denne vejledning har vi diskuteret deadlock og livelock. Vi har også undersøgt Java-eksempler for at demonstrere hvert af disse problemer og kort berørt, hvordan vi kan undgå dem.

Som altid kan den komplette kode, der bruges i dette eksempel, findes på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found