Lås og Betingelse
I Java er standard synkronisering basert på nøkkelordet synchronized og innebygde monitorobjekter. I noen tilfeller kan imidlertid synchronized være utilstrekkelig, spesielt når det kreves større fleksibilitet i trådhåndtering.
Generell beskrivelse
Lock-grensesnittet og Condition-grensesnittet, introdusert i pakken java.util.concurrent.locks, gir avanserte muligheter for trådhåndtering.
I dette bildet kan du se at første tråd tar låsen ved å bruke lock()-metoden, og på dette tidspunktet kan en annen tråd ikke ta den samme låsen. Så snart all koden inne i låsen er utført, vil den kalle unlock()-metoden og frigjøre låsen. Først etter dette kan andre tråd ta låsen.
Forskjell
Forskjellen mellom disse to grensesnittene er at Lock-implementasjoner er et høynivå alternativ til synchronized-blokken, og Condition-grensesnitt-implementasjoner er et alternativ til notify()/wait()-metodene. Begge disse grensesnittene er en del av pakken java.util.concurrent.locks.
Virkelige eksempler
Tenk deg at du administrerer en kø for registrering til et arrangement. For å forhindre overflyt og sikre korrekt seteallokering, må du bruke blokkeringsmekanismer og betingelser for å holde nye registreringer ventende til en ledig plass blir tilgjengelig.
ReentrantLock-klassen
ReentrantLock-klassen fra java.util.concurrent.locks-pakken er en implementasjon av Lock-grensesnittet. Den gir funksjonalitet for eksplisitt håndtering av låser.
Hovedmetoder i ReentrantLock:
lock(): Tar en lås;unlock(): Frigir låsen;tryLock(): Prøver å ta låsen og returnerer true hvis det lykkes;tryLock(long timeout, TimeUnit unit): Prøver å ta låsen i en angitt tidsperiode;newCondition(): Oppretter en betingelse for gjeldendeLock.
Main.java
12345678910111213141516171819202122232425262728293031package com.example; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Main { // Creating a ReentrantLock object private final Lock lock = new ReentrantLock(); private int count = 0; // Method to increment the `count` variable public void increment() { lock.lock(); // Acquiring the `lock` try { count++; System.out.println("Count incremented to: " + count); } finally { lock.unlock(); // Releasing the `lock` } } public static void main(String[] args) { Main example = new Main(); // Runnable task to call the increment method Runnable task = example::increment; // Starting multiple threads to execute the task for (int i = 0; i < 5; i++) { new Thread(task).start(); } } }
Som du kan se, i increment()-metoden bruker vi låsing med Lock. Når en tråd går inn i metoden, tar den låsen med lock.lock(), deretter utføres koden, og til slutt frigjøres låsen i finally-blokken med lock.unlock(), slik at andre tråder kan få tilgang.
Vi frigjør låsen i finally-blokken av en grunn, nemlig at denne blokken nesten alltid blir utført, selv ved unntak, bortsett fra når programmet avsluttes.
Condition-grensesnitt
Vi kan kun opprette et Condition-objekt med tilknytning til en spesifikk Lock-implementasjon. Av denne grunn vil Condition-metodene kun påvirke låsingen til den aktuelle Lock-implementasjonen.
Main.java
12private final Lock lock = new ReentrantLock(); private final Condition condition = lock.newCondition();
Hovedmetodene til Condition:
await(): Venter på et signal fra en annen tråd;signal(): Låser opp én tråd som venter på en betingelse;signalAll(): Låser opp alle tråder som venter på betingelsen.
Main.java
12345678910111213141516private final ReentrantLock lock = new ReentrantLock(); private final Condition condition = lock.newCondition(); private boolean ready = false; public void waitForCondition() throws InterruptedException { lock.lock(); // Acquire the `lock` try { while (!ready) { // Check if the condition is not met System.out.println("Waiting..."); // Print a waiting message condition.await(); // Wait for the condition to be signaled } System.out.println("Condition met!"); // Print a message when the condition is met } finally { lock.unlock(); // Release the `lock` } }
Metoden waitForCondition() blokkerer tråden til variabelen ready blir true, noe som signaliserer at betingelsen er oppfylt. Når betingelsen er oppfylt, fortsetter tråden å kjøre og viser meldingen “Condition met!”
Når metoden await() kalles, blir tråden pauset og frigjør også låsen den har tatt. Når tråden våkner, må den ta låsen på nytt, og først da vil den begynne å utføre!
Kodeeksempel
Nå skal vi se på et eksempel på bruk av ReentrantLock og Condition for å håndtere registrering til et arrangement:
Et kort klipp fra videoen
Låsing med ReentrantLock: Metoden register() tar låsen med lock.lock() for å forhindre at flere tråder kjører koden samtidig.
Betingelse med Condition: Hvis det ikke er ledige plasser, kaller tråden spaceAvailable.await() for å vente til det blir ledig plass.
Frigi lås: Når en tråd har frigitt plass ved å bruke metoden cancel(), kaller den spaceAvailable.signalAll() for å varsle alle ventende tråder.
Unntakshåndtering: Bruk av try-finally-blokker sikrer at låsen frigjøres selv om det oppstår et unntak.
Bruken av Lock og Condition i Java gir mer fleksibel kontroll over tråder og synkronisering enn den tradisjonelle synchronized-mekanismen. Dette er spesielt nyttig i komplekse scenarier hvor mer presis kontroll over tråder og ventebetingelser er nødvendig.
Takk for tilbakemeldingene dine!
Spør AI
Spør AI
Spør om hva du vil, eller prøv ett av de foreslåtte spørsmålene for å starte chatten vår
Awesome!
Completion rate improved to 3.33
Lås og Betingelse
Sveip for å vise menyen
I Java er standard synkronisering basert på nøkkelordet synchronized og innebygde monitorobjekter. I noen tilfeller kan imidlertid synchronized være utilstrekkelig, spesielt når det kreves større fleksibilitet i trådhåndtering.
Generell beskrivelse
Lock-grensesnittet og Condition-grensesnittet, introdusert i pakken java.util.concurrent.locks, gir avanserte muligheter for trådhåndtering.
I dette bildet kan du se at første tråd tar låsen ved å bruke lock()-metoden, og på dette tidspunktet kan en annen tråd ikke ta den samme låsen. Så snart all koden inne i låsen er utført, vil den kalle unlock()-metoden og frigjøre låsen. Først etter dette kan andre tråd ta låsen.
Forskjell
Forskjellen mellom disse to grensesnittene er at Lock-implementasjoner er et høynivå alternativ til synchronized-blokken, og Condition-grensesnitt-implementasjoner er et alternativ til notify()/wait()-metodene. Begge disse grensesnittene er en del av pakken java.util.concurrent.locks.
Virkelige eksempler
Tenk deg at du administrerer en kø for registrering til et arrangement. For å forhindre overflyt og sikre korrekt seteallokering, må du bruke blokkeringsmekanismer og betingelser for å holde nye registreringer ventende til en ledig plass blir tilgjengelig.
ReentrantLock-klassen
ReentrantLock-klassen fra java.util.concurrent.locks-pakken er en implementasjon av Lock-grensesnittet. Den gir funksjonalitet for eksplisitt håndtering av låser.
Hovedmetoder i ReentrantLock:
lock(): Tar en lås;unlock(): Frigir låsen;tryLock(): Prøver å ta låsen og returnerer true hvis det lykkes;tryLock(long timeout, TimeUnit unit): Prøver å ta låsen i en angitt tidsperiode;newCondition(): Oppretter en betingelse for gjeldendeLock.
Main.java
12345678910111213141516171819202122232425262728293031package com.example; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Main { // Creating a ReentrantLock object private final Lock lock = new ReentrantLock(); private int count = 0; // Method to increment the `count` variable public void increment() { lock.lock(); // Acquiring the `lock` try { count++; System.out.println("Count incremented to: " + count); } finally { lock.unlock(); // Releasing the `lock` } } public static void main(String[] args) { Main example = new Main(); // Runnable task to call the increment method Runnable task = example::increment; // Starting multiple threads to execute the task for (int i = 0; i < 5; i++) { new Thread(task).start(); } } }
Som du kan se, i increment()-metoden bruker vi låsing med Lock. Når en tråd går inn i metoden, tar den låsen med lock.lock(), deretter utføres koden, og til slutt frigjøres låsen i finally-blokken med lock.unlock(), slik at andre tråder kan få tilgang.
Vi frigjør låsen i finally-blokken av en grunn, nemlig at denne blokken nesten alltid blir utført, selv ved unntak, bortsett fra når programmet avsluttes.
Condition-grensesnitt
Vi kan kun opprette et Condition-objekt med tilknytning til en spesifikk Lock-implementasjon. Av denne grunn vil Condition-metodene kun påvirke låsingen til den aktuelle Lock-implementasjonen.
Main.java
12private final Lock lock = new ReentrantLock(); private final Condition condition = lock.newCondition();
Hovedmetodene til Condition:
await(): Venter på et signal fra en annen tråd;signal(): Låser opp én tråd som venter på en betingelse;signalAll(): Låser opp alle tråder som venter på betingelsen.
Main.java
12345678910111213141516private final ReentrantLock lock = new ReentrantLock(); private final Condition condition = lock.newCondition(); private boolean ready = false; public void waitForCondition() throws InterruptedException { lock.lock(); // Acquire the `lock` try { while (!ready) { // Check if the condition is not met System.out.println("Waiting..."); // Print a waiting message condition.await(); // Wait for the condition to be signaled } System.out.println("Condition met!"); // Print a message when the condition is met } finally { lock.unlock(); // Release the `lock` } }
Metoden waitForCondition() blokkerer tråden til variabelen ready blir true, noe som signaliserer at betingelsen er oppfylt. Når betingelsen er oppfylt, fortsetter tråden å kjøre og viser meldingen “Condition met!”
Når metoden await() kalles, blir tråden pauset og frigjør også låsen den har tatt. Når tråden våkner, må den ta låsen på nytt, og først da vil den begynne å utføre!
Kodeeksempel
Nå skal vi se på et eksempel på bruk av ReentrantLock og Condition for å håndtere registrering til et arrangement:
Et kort klipp fra videoen
Låsing med ReentrantLock: Metoden register() tar låsen med lock.lock() for å forhindre at flere tråder kjører koden samtidig.
Betingelse med Condition: Hvis det ikke er ledige plasser, kaller tråden spaceAvailable.await() for å vente til det blir ledig plass.
Frigi lås: Når en tråd har frigitt plass ved å bruke metoden cancel(), kaller den spaceAvailable.signalAll() for å varsle alle ventende tråder.
Unntakshåndtering: Bruk av try-finally-blokker sikrer at låsen frigjøres selv om det oppstår et unntak.
Bruken av Lock og Condition i Java gir mer fleksibel kontroll over tråder og synkronisering enn den tradisjonelle synchronized-mekanismen. Dette er spesielt nyttig i komplekse scenarier hvor mer presis kontroll over tråder og ventebetingelser er nødvendig.
Takk for tilbakemeldingene dine!