Java trådlås og livelock

1. Oversikt

Mens multi-threading hjelper til med å forbedre applikasjonens ytelse, kommer det også med noen problemer. I denne opplæringen vil vi se på to slike problemer, fastlåst og livelock, ved hjelp av Java-eksempler.

2. Dødlås

2.1. Hva er Deadlock?

En fastlåst oppstår når to eller flere tråder venter for alltid på en lås eller ressurs som en annen av trådene har. Derfor kan et program stoppe eller mislykkes ettersom de fastlåste trådene ikke kan utvikle seg.

Det klassiske spisefilosofens problem demonstrerer pent synkroniseringsproblemene i et miljø med flere tråder og brukes ofte som et eksempel på fastlåst tilstand.

2.2. Deadlock Eksempel

Først, la oss se på et enkelt Java-eksempel for å forstå fastlåst tilstand.

I dette eksemplet lager vi to tråder, T1 og T2. Tråd T1 ringer betjening1, og tråd T2 ringer operasjoner.

For å fullføre operasjonene, tråd T1 trenger å anskaffe lås 1 først og deretter lås2mens tråd T2 trenger å anskaffe lås2 først og deretter lås 1. Så i utgangspunktet prøver begge trådene å skaffe låsene i motsatt rekkefølge.

La oss nå skrive DeadlockExample klasse:

offentlig klasse DeadlockExample {private Lock lock1 = new ReentrantLock (true); private Lock lock2 = nye ReentrantLock (true); public static void main (String [] args) {DeadlockExample deadlock = new DeadlockExample (); new Thread (deadlock :: operation1, "T1"). start (); new Thread (deadlock :: operation2, "T2"). start (); } offentlig ugyldig drift1 () {lock1.lock (); print ("lock1 ervervet, venter på å anskaffe lock2."); søvn (50); lås2.lås (); utskrift ("lock2 ervervet"); utskrift ("utfører første operasjon."); lock2.unlock (); lock1.unlock (); } offentlig ugyldig drift2 () {lock2.lock (); print ("lock2 ervervet, venter på å anskaffe lock1."); søvn (50); lock1.lock (); utskrift ("lock1 ervervet"); print ("utfører andre operasjon."); lock1.unlock (); lock2.unlock (); } // hjelpemetoder}

La oss nå kjøre dette dødlåseksemplet og legge merke til utgangen:

Tråd T1: lås1 ervervet, venter på å skaffe seg lås2. Tråd T2: lås2 ervervet, venter på å skaffe lås1.

Når vi har kjørt programmet, kan vi se at programmet resulterer i en fastlåst tilstand og aldri går ut. Loggen viser den tråden T1 venter på lås2, som holdes av tråden T2. Tilsvarende, tråd T2 venter på lås 1, som holdes av tråden T1.

2.3. Unngå fastlåst

Deadlock er et vanlig samtidighetsproblem i Java. Derfor bør vi designe et Java-program for å unngå potensielle låseforhold.

Til å begynne med bør vi unngå behovet for å anskaffe flere låser for en tråd. Imidlertid, hvis en tråd trenger flere låser, bør vi sørge for at hver tråd får låser i samme rekkefølge, til unngå syklisk avhengighet ved låseanskaffelse.

Vi kan også bruke tidsbestemte låseforsøk, som tryLock metoden i Låse grensesnitt, for å sikre at en tråd ikke blokkeres uendelig hvis den ikke klarer å skaffe seg en lås.

3. Livelock

3.1. Hva er Livelock

Livelock er et annet samtidighetsproblem og ligner på fastlåst. I husdyr, to eller flere tråder fortsetter å overføre tilstander mellom hverandre i stedet for å vente uendelig som vi så i blindlåseeksemplet. Følgelig er ikke trådene i stand til å utføre sine respektive oppgaver.

Et godt eksempel på livelock er et meldingssystem der meldingsforbrukeren, når et unntak oppstår, ruller tilbake transaksjonen og setter meldingen tilbake til køhodet. Deretter leses den samme meldingen gjentatte ganger fra køen, bare for å forårsake et annet unntak og settes tilbake i køen. Forbrukeren vil aldri hente noen annen melding fra køen.

3.2. Livelock Eksempel

Nå, for å demonstrere livelock-tilstanden, tar vi det samme låseksemplet som vi har diskutert tidligere. Også i dette eksemplet, tråd T1 ringer betjening1 og tråd T2 ringer drift2. Imidlertid vil vi endre logikken i disse operasjonene litt.

Begge trådene trenger to låser for å fullføre arbeidet. Hver tråd får sin første lås, men finner ut at den andre låsen ikke er tilgjengelig. Så, for å la den andre tråden fullføre først, frigjør hver tråd sin første lås og prøver å skaffe begge låsene igjen.

La oss demonstrere livelock med en Livelock Eksempel klasse:

offentlig klasse LivelockExample {private Lock lock1 = new ReentrantLock (true); private Lock lock2 = nye ReentrantLock (true); public static void main (String [] args) {LivelockExample livelock = new LivelockExample (); new Thread (livelock :: operation1, "T1"). start (); ny tråd (livelock :: operation2, "T2"). start (); } offentlig ugyldig drift1 () {while (true) {tryLock (lock1, 50); print ("lock1 ervervet, prøver å skaffe lock2."); søvn (50); hvis (tryLock (lock2)) {print ("lock2 ervervet."); } annet {print ("kan ikke skaffe lock2, frigjøre lock1."); lock1.unlock (); Fortsette; } print ("utfører første operasjon."); gå i stykker; } lock2.unlock (); lock1.unlock (); } public void operation2 () {while (true) {tryLock (lock2, 50); print ("lock2 ervervet, prøver å anskaffe lock1."); søvn (50); hvis (tryLock (lock1)) {print ("lock1 ervervet."); } annet {print ("kan ikke anskaffe lås1, frigjør lås2."); lock2.unlock (); Fortsette; } utskrift ("utfører andre operasjoner."); gå i stykker; } lock1.unlock (); lock2.unlock (); } // hjelpemetoder}

La oss kjøre dette eksemplet:

Tråd T1: lock1 ervervet, prøver å skaffe lock2. Tråd T2: lock2 ervervet, prøver å skaffe lock1. Tråd T1: kan ikke skaffe seg lås2, frigjør lås1. Tråd T2: kan ikke skaffe seg lås1, frigjør lås2. Tråd T2: lock2 ervervet, prøver å skaffe lock1. Tråd T1: lock1 ervervet, prøver å skaffe lock2. Tråd T1: kan ikke skaffe seg lås2, frigjør lås1. Tråd T1: lock1 ervervet, prøver å skaffe lock2. Tråd T2: kan ikke skaffe seg lås1, frigjør lås2. ..

Som vi kan se i loggene, får begge trådene gjentatte ganger låser og slipper. På grunn av dette er ingen av trådene i stand til å fullføre operasjonen.

3.3. Unngå Livelock

For å unngå husdyr, må vi se på tilstanden som forårsaker livmassen, og deretter finne en løsning deretter.

For eksempel, hvis vi har to tråder som gjentatte ganger skaffer og slipper låser, noe som resulterer i livelock, kan vi designe koden slik at trådene prøver å anskaffe låsene på tilfeldige intervaller. Dette vil gi trådene en god sjanse til å anskaffe låsene de trenger.

En annen måte å ta vare på livsproblemet i meldingssystemeksemplet vi har diskutert tidligere, er å plassere mislykkede meldinger i en egen kø for videre behandling i stedet for å sette dem tilbake i samme kø igjen.

4. Konklusjon

I denne opplæringen har vi diskutert fastlåst og livelock. Vi har også sett på Java-eksempler for å demonstrere hvert av disse problemene og kort berørt hvordan vi kan unngå dem.

Som alltid kan den komplette koden som brukes i dette eksemplet finnes på GitHub.