Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Lære Lås og Betingelse | Høynivå Synkroniseringsmekanismer
Quizzes & Challenges
Quizzes
Challenges
/
Multitråding i Java

bookLå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 gjeldende Lock.
Main.java

Main.java

copy
12345678910111213141516171819202122232425262728293031
package 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

Main.java

copy
12
private 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

Main.java

copy
12345678910111213141516
private 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!”

Note
Merk

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.

Note
Merk

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.

Alt var klart?

Hvordan kan vi forbedre det?

Takk for tilbakemeldingene dine!

Seksjon 3. Kapittel 1

Spør AI

expand

Spør AI

ChatGPT

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

bookLå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 gjeldende Lock.
Main.java

Main.java

copy
12345678910111213141516171819202122232425262728293031
package 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

Main.java

copy
12
private 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

Main.java

copy
12345678910111213141516
private 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!”

Note
Merk

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.

Note
Merk

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.

Alt var klart?

Hvordan kan vi forbedre det?

Takk for tilbakemeldingene dine!

Seksjon 3. Kapittel 1
some-alt