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

bookSemafor og Barriere

I multitrådede programmer er det ofte nødvendig å kontrollere tilgangen til ressurser eller synkronisere tråders utførelse. Semaphore og Barrier er høynivå synkroniseringsmekanismer som hjelper til med å løse disse utfordringene.

I dag skal vi utforske hver av disse mekanismene i rekkefølge og forstå forskjellene mellom dem. Vi begynner med Semaphore.

Semaphore i Java er implementert gjennom klassen java.util.concurrent.Semaphore.

Konstruktører

Semaphore(int permits): Konstruktør som oppretter en semaphore med et bestemt antall tillatelser. Tillatelsene representerer antall tilganger til den delte ressursen.

Main.java

Main.java

copy
1
Semaphore semaphore = new Semaphore(20);

Semaphore(int permits, boolean fair): Konstruktør som gir førstemann til mølla- og først til mølla-løsning.

Main.java

Main.java

copy
1
Semaphore semaphore = new Semaphore(20, true);

Hvis fair er satt til true, vil semaphore tildele tillatelser i først-inn-først-ut (FIFO)-rekkefølge, noe som kan bidra til å unngå sult. Standardverdi - false.

Hovedmetoder

Metoden acquire() ber om en enkelt tillatelse. Hvis en tillatelse er tilgjengelig, blir den gitt umiddelbart; ellers blir tråden blokkert til en tillatelse blir tilgjengelig. Når en oppgave er fullført, brukes metoden release() for å frigjøre tillatelsen, slik at den returneres til semaphore. Hvis andre tråder ventet på en tillatelse, vil én av dem bli avblokkert.

Tenk deg en parkeringsplass med et begrenset antall plasser. semaphore fungerer som en kontrollør som holder oversikt over tilgjengelige plasser og nekter tilgang når plassen er full.

Main.java

Main.java

copy
1234567891011121314151617181920212223242526272829303132
package com.example; import java.util.concurrent.Semaphore; public class Main { private final Semaphore semaphore; public Main(int slots) { semaphore = new Semaphore(slots); } public void parkCar() { try { semaphore.acquire(); // Request a parking spot System.out.println("Car parked. Available slots: " + semaphore.availablePermits()); Thread.sleep(2000); // Simulate parking time } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { semaphore.release(); // Release the parking spot System.out.println("Car left. Available slots: " + semaphore.availablePermits()); } } public static void main(String[] args) { Main parking = new Main(3); // Parking lot with 3 spots for (int i = 0; i < 5; i++) { new Thread(parking::parkCar).start(); } } }

Du kan også finne ut hvor mange tillatelser som for øyeblikket er tilgjengelige i Semaphore ved å bruke metoden int availablePermits(). Det er også mulig å forsøke å skaffe en tillatelse ved hjelp av metoden boolean tryAcquire(), som returnerer true hvis en tillatelse ble oppnådd og false hvis ikke.

Main.java

Main.java

copy
1234567891011121314151617181920212223242526272829303132333435363738394041
package com.example; import java.util.concurrent.Semaphore; public class Main { // Define the maximum number of permits available private static final int MAX_PERMITS = 3; private static Semaphore semaphore = new Semaphore(MAX_PERMITS); public static void main(String[] args) { // Create and start 5 worker threads for (int i = 1; i <= 5; i++) { new Thread(new Worker(), "Worker-" + i).start(); } } static class Worker implements Runnable { @Override public void run() { String name = Thread.currentThread().getName(); System.out.println(name + " trying to acquire a permit..."); // Try to acquire a permit if (semaphore.tryAcquire()) { try { System.out.println(name + " acquired a permit! Available permits: " + semaphore.availablePermits()); Thread.sleep(1000); // Simulate work } catch (InterruptedException e) { e.printStackTrace(); } finally { // Release the permit after the work is done semaphore.release(); System.out.println(name + " released a permit. Available permits: " + semaphore.availablePermits()); } } else { // Inform if the permit could not be acquired System.out.println(name + " could not acquire a permit. Available permits: " + semaphore.availablePermits()); } } } }
Note
Merk

Med andre ord er en Semaphore nyttig når det er behov for begrenset samtidig tilgang til en bestemt kode­del. Den eneste ulempen er muligheten for død­lås dersom tråder blir blokkert i feil rekkefølge.

La oss nå gå videre til neste synkroniseringsmekanisme, som er enda enklere å bruke, men vil være hundre prosent verdifull for dine behov.

CyclicBarrier

Barrier i Java er representert av klassen java.util.concurrent.CyclicBarrier. De viktigste metodene til CyclicBarrier inkluderer:

Konstruktører CyclicBarrier

CyclicBarrier(int parties): Konstruktør som oppretter en barriere som blokkerer tråder til et bestemt antall tråder (parties) har ankommet.

Main.java

Main.java

copy
1
CyclicBarrier cyclicBarrier = new CyclicBarrier(10);

CyclicBarrier(int parties, Runnable barrierAction): Konstruktør som oppretter en barriere med et angitt antall parter og en handling (barrierAction) som utføres når alle parter ankommer barrieren.

Main.java

Main.java

copy
1234567
Runnable task = () -> { // This task will be executed when all parties have reached the barrier System.out.println("Hello))"); }; // Create a `CyclicBarrier` for 10 parties with a barrier action CyclicBarrier cyclicBarrier = new CyclicBarrier(10, task);

Metoder i CyclicBarrier

Hovedmetoden await() brukes som en barriere og lar ikke tråden fortsette før alle tråder har nådd denne metoden. Returnerer et sekvensnummer som indikerer rekkefølgen deltakerne ankommer i.

Main.java

Main.java

copy
1234567891011121314151617181920212223242526272829303132333435363738394041424344
package com.example; import java.util.concurrent.CyclicBarrier; public class Main { public static void main(String[] args) { // Create a `CyclicBarrier` for 3 parties with a barrier action CyclicBarrier barrier = new CyclicBarrier(3, () -> { System.out.println("All parties have reached the barrier. Barrier action executed."); }); // Create and start 3 worker threads for (int i = 1; i <= 3; i++) { new Thread(new Worker(barrier), "Worker-" + i).start(); } } static class Worker implements Runnable { private CyclicBarrier barrier; Worker(CyclicBarrier barrier) { this.barrier = barrier; } @Override public void run() { String name = Thread.currentThread().getName(); System.out.println(name + " is working..."); try { // Simulate work Thread.sleep((int) (Math.random() * 1000)); System.out.println(name + " is waiting at the barrier."); barrier.await(); // Wait at the barrier // This code will execute after all parties have reached the barrier System.out.println(name + " has crossed the barrier."); } catch (Exception e) { e.printStackTrace(); } } } }

Det kan hende at ikke alle tråder vil nå barrieren, og programmet vil henge. For dette formålet brukes metoden await(long timeout, TimeUnit unit), som ligner på await(), men med tidsavbrudd. Hvis tidsavbruddet utløper før alle deltakerne ankommer, kaster metoden et TimeoutException-unntak.

Du kan også finne ut antallet deltakere som kreves for å fullføre barrieren med int getParties(), samt en lignende metode int getNumberWaiting() som returnerer antall deltakere som for øyeblikket venter ved barrieren.

Main.java

Main.java

copy
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
package com.example; import java.util.concurrent.CyclicBarrier; public class Main { public static void main(String[] args) { // Create a `CyclicBarrier` for 3 parties with a barrier action CyclicBarrier barrier = new CyclicBarrier(3, () -> { System.out.println("All parties have reached the barrier. Barrier action executed."); }); System.out.println("Total number of parties required to complete the barrier: " + barrier.getParties()); // Create and start 3 worker threads for (int i = 1; i <= 3; i++) { new Thread(new Worker(barrier), "Worker-" + i).start(); } } static class Worker implements Runnable { private CyclicBarrier barrier; Worker(CyclicBarrier barrier) { this.barrier = barrier; } @Override public void run() { String name = Thread.currentThread().getName(); System.out.println(name + " is working..."); try { // Simulate work Thread.sleep((int) (Math.random() * 1000)); System.out.println(name + " is waiting at the barrier."); barrier.await(); // Wait at the barrier // This code will execute after all parties have reached the barrier System.out.println(name + " has crossed the barrier."); } catch (Exception e) { e.printStackTrace(); } // Print the number of participants currently waiting at the barrier System.out.println("Number of participants currently waiting at the barrier: " + barrier.getNumberWaiting()); } } }

Det er også mulig å sjekke om barrieren har blitt ødelagt hvis en av trådene blir avbrutt eller hvis ventetiden har utløpt, ved å bruke metoden boolean isBroken(). Hvis den har blitt ødelagt, kan du bruke metoden void reset() som enkelt gjenoppretter barrieren.

Main.java

Main.java

copy
12345
// Check if the barrier is broken and reset it if necessary if (barrier.isBroken()) { System.out.println("Barrier is broken. Resetting the barrier."); barrier.reset(); }
Note
Merk

Det bør tas i betraktning at noen tråder kanskje ikke når barrieren på grunn av en feil eller andre årsaker, og da er det klart at barrieren ikke vil slippe gjennom de trådene som for øyeblikket venter ved barrieren.

Alt var klart?

Hvordan kan vi forbedre det?

Takk for tilbakemeldingene dine!

Seksjon 3. Kapittel 3

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

bookSemafor og Barriere

Sveip for å vise menyen

I multitrådede programmer er det ofte nødvendig å kontrollere tilgangen til ressurser eller synkronisere tråders utførelse. Semaphore og Barrier er høynivå synkroniseringsmekanismer som hjelper til med å løse disse utfordringene.

I dag skal vi utforske hver av disse mekanismene i rekkefølge og forstå forskjellene mellom dem. Vi begynner med Semaphore.

Semaphore i Java er implementert gjennom klassen java.util.concurrent.Semaphore.

Konstruktører

Semaphore(int permits): Konstruktør som oppretter en semaphore med et bestemt antall tillatelser. Tillatelsene representerer antall tilganger til den delte ressursen.

Main.java

Main.java

copy
1
Semaphore semaphore = new Semaphore(20);

Semaphore(int permits, boolean fair): Konstruktør som gir førstemann til mølla- og først til mølla-løsning.

Main.java

Main.java

copy
1
Semaphore semaphore = new Semaphore(20, true);

Hvis fair er satt til true, vil semaphore tildele tillatelser i først-inn-først-ut (FIFO)-rekkefølge, noe som kan bidra til å unngå sult. Standardverdi - false.

Hovedmetoder

Metoden acquire() ber om en enkelt tillatelse. Hvis en tillatelse er tilgjengelig, blir den gitt umiddelbart; ellers blir tråden blokkert til en tillatelse blir tilgjengelig. Når en oppgave er fullført, brukes metoden release() for å frigjøre tillatelsen, slik at den returneres til semaphore. Hvis andre tråder ventet på en tillatelse, vil én av dem bli avblokkert.

Tenk deg en parkeringsplass med et begrenset antall plasser. semaphore fungerer som en kontrollør som holder oversikt over tilgjengelige plasser og nekter tilgang når plassen er full.

Main.java

Main.java

copy
1234567891011121314151617181920212223242526272829303132
package com.example; import java.util.concurrent.Semaphore; public class Main { private final Semaphore semaphore; public Main(int slots) { semaphore = new Semaphore(slots); } public void parkCar() { try { semaphore.acquire(); // Request a parking spot System.out.println("Car parked. Available slots: " + semaphore.availablePermits()); Thread.sleep(2000); // Simulate parking time } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { semaphore.release(); // Release the parking spot System.out.println("Car left. Available slots: " + semaphore.availablePermits()); } } public static void main(String[] args) { Main parking = new Main(3); // Parking lot with 3 spots for (int i = 0; i < 5; i++) { new Thread(parking::parkCar).start(); } } }

Du kan også finne ut hvor mange tillatelser som for øyeblikket er tilgjengelige i Semaphore ved å bruke metoden int availablePermits(). Det er også mulig å forsøke å skaffe en tillatelse ved hjelp av metoden boolean tryAcquire(), som returnerer true hvis en tillatelse ble oppnådd og false hvis ikke.

Main.java

Main.java

copy
1234567891011121314151617181920212223242526272829303132333435363738394041
package com.example; import java.util.concurrent.Semaphore; public class Main { // Define the maximum number of permits available private static final int MAX_PERMITS = 3; private static Semaphore semaphore = new Semaphore(MAX_PERMITS); public static void main(String[] args) { // Create and start 5 worker threads for (int i = 1; i <= 5; i++) { new Thread(new Worker(), "Worker-" + i).start(); } } static class Worker implements Runnable { @Override public void run() { String name = Thread.currentThread().getName(); System.out.println(name + " trying to acquire a permit..."); // Try to acquire a permit if (semaphore.tryAcquire()) { try { System.out.println(name + " acquired a permit! Available permits: " + semaphore.availablePermits()); Thread.sleep(1000); // Simulate work } catch (InterruptedException e) { e.printStackTrace(); } finally { // Release the permit after the work is done semaphore.release(); System.out.println(name + " released a permit. Available permits: " + semaphore.availablePermits()); } } else { // Inform if the permit could not be acquired System.out.println(name + " could not acquire a permit. Available permits: " + semaphore.availablePermits()); } } } }
Note
Merk

Med andre ord er en Semaphore nyttig når det er behov for begrenset samtidig tilgang til en bestemt kode­del. Den eneste ulempen er muligheten for død­lås dersom tråder blir blokkert i feil rekkefølge.

La oss nå gå videre til neste synkroniseringsmekanisme, som er enda enklere å bruke, men vil være hundre prosent verdifull for dine behov.

CyclicBarrier

Barrier i Java er representert av klassen java.util.concurrent.CyclicBarrier. De viktigste metodene til CyclicBarrier inkluderer:

Konstruktører CyclicBarrier

CyclicBarrier(int parties): Konstruktør som oppretter en barriere som blokkerer tråder til et bestemt antall tråder (parties) har ankommet.

Main.java

Main.java

copy
1
CyclicBarrier cyclicBarrier = new CyclicBarrier(10);

CyclicBarrier(int parties, Runnable barrierAction): Konstruktør som oppretter en barriere med et angitt antall parter og en handling (barrierAction) som utføres når alle parter ankommer barrieren.

Main.java

Main.java

copy
1234567
Runnable task = () -> { // This task will be executed when all parties have reached the barrier System.out.println("Hello))"); }; // Create a `CyclicBarrier` for 10 parties with a barrier action CyclicBarrier cyclicBarrier = new CyclicBarrier(10, task);

Metoder i CyclicBarrier

Hovedmetoden await() brukes som en barriere og lar ikke tråden fortsette før alle tråder har nådd denne metoden. Returnerer et sekvensnummer som indikerer rekkefølgen deltakerne ankommer i.

Main.java

Main.java

copy
1234567891011121314151617181920212223242526272829303132333435363738394041424344
package com.example; import java.util.concurrent.CyclicBarrier; public class Main { public static void main(String[] args) { // Create a `CyclicBarrier` for 3 parties with a barrier action CyclicBarrier barrier = new CyclicBarrier(3, () -> { System.out.println("All parties have reached the barrier. Barrier action executed."); }); // Create and start 3 worker threads for (int i = 1; i <= 3; i++) { new Thread(new Worker(barrier), "Worker-" + i).start(); } } static class Worker implements Runnable { private CyclicBarrier barrier; Worker(CyclicBarrier barrier) { this.barrier = barrier; } @Override public void run() { String name = Thread.currentThread().getName(); System.out.println(name + " is working..."); try { // Simulate work Thread.sleep((int) (Math.random() * 1000)); System.out.println(name + " is waiting at the barrier."); barrier.await(); // Wait at the barrier // This code will execute after all parties have reached the barrier System.out.println(name + " has crossed the barrier."); } catch (Exception e) { e.printStackTrace(); } } } }

Det kan hende at ikke alle tråder vil nå barrieren, og programmet vil henge. For dette formålet brukes metoden await(long timeout, TimeUnit unit), som ligner på await(), men med tidsavbrudd. Hvis tidsavbruddet utløper før alle deltakerne ankommer, kaster metoden et TimeoutException-unntak.

Du kan også finne ut antallet deltakere som kreves for å fullføre barrieren med int getParties(), samt en lignende metode int getNumberWaiting() som returnerer antall deltakere som for øyeblikket venter ved barrieren.

Main.java

Main.java

copy
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
package com.example; import java.util.concurrent.CyclicBarrier; public class Main { public static void main(String[] args) { // Create a `CyclicBarrier` for 3 parties with a barrier action CyclicBarrier barrier = new CyclicBarrier(3, () -> { System.out.println("All parties have reached the barrier. Barrier action executed."); }); System.out.println("Total number of parties required to complete the barrier: " + barrier.getParties()); // Create and start 3 worker threads for (int i = 1; i <= 3; i++) { new Thread(new Worker(barrier), "Worker-" + i).start(); } } static class Worker implements Runnable { private CyclicBarrier barrier; Worker(CyclicBarrier barrier) { this.barrier = barrier; } @Override public void run() { String name = Thread.currentThread().getName(); System.out.println(name + " is working..."); try { // Simulate work Thread.sleep((int) (Math.random() * 1000)); System.out.println(name + " is waiting at the barrier."); barrier.await(); // Wait at the barrier // This code will execute after all parties have reached the barrier System.out.println(name + " has crossed the barrier."); } catch (Exception e) { e.printStackTrace(); } // Print the number of participants currently waiting at the barrier System.out.println("Number of participants currently waiting at the barrier: " + barrier.getNumberWaiting()); } } }

Det er også mulig å sjekke om barrieren har blitt ødelagt hvis en av trådene blir avbrutt eller hvis ventetiden har utløpt, ved å bruke metoden boolean isBroken(). Hvis den har blitt ødelagt, kan du bruke metoden void reset() som enkelt gjenoppretter barrieren.

Main.java

Main.java

copy
12345
// Check if the barrier is broken and reset it if necessary if (barrier.isBroken()) { System.out.println("Barrier is broken. Resetting the barrier."); barrier.reset(); }
Note
Merk

Det bør tas i betraktning at noen tråder kanskje ikke når barrieren på grunn av en feil eller andre årsaker, og da er det klart at barrieren ikke vil slippe gjennom de trådene som for øyeblikket venter ved barrieren.

Alt var klart?

Hvordan kan vi forbedre det?

Takk for tilbakemeldingene dine!

Seksjon 3. Kapittel 3
some-alt