Semafor og Barriere
I multitrådede programmer er det ofte nødvendigt at kontrollere adgangen til ressourcer eller synkronisere trådenes udførelse. Semaphore og Barrier er højniveau synkroniseringsmekanismer, der hjælper med at håndtere disse udfordringer.
I dag vil vi undersøge hver af disse mekanismer i rækkefølge og forstå deres forskelle. Lad os begynde med Semaphore.
Semaphore i Java implementeres gennem klassen java.util.concurrent.Semaphore.
Konstruktører
Semaphore(int permits): Konstruktør, der opretter en semaphore med et bestemt antal tilladelser. Tilladelserne repræsenterer antallet af adgange til den delte ressource.
Main.java
1Semaphore semaphore = new Semaphore(20);
Semaphore(int permits, boolean fair): Konstruktør, der sikrer først-til-mølle-princippet.
Main.java
1Semaphore semaphore = new Semaphore(20, true);
Hvis fair er sat til true, vil semaphore tildele tilladelser i først-ind-først-ud (FIFO) rækkefølge, hvilket kan hjælpe med at undgå sult. Standard - false.
Hovedmetoder
Metoden acquire() anmoder om en enkelt tilladelse. Hvis en tilladelse er tilgængelig, tildeles den straks; ellers bliver tråden blokeret, indtil en tilladelse bliver tilgængelig. Når en opgave er fuldført, bruges metoden release() til at frigive tilladelsen og returnere den til semaphore. Hvis andre tråde ventede på en tilladelse, vil én af dem blive afblokeret.
Forestil dig en parkeringsplads med et begrænset antal pladser. semaphore fungerer som en kontrolinstans, der holder styr på de tilgængelige pladser og afviser adgang, når pladsen er fuld.
Main.java
1234567891011121314151617181920212223242526272829303132package 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å finde ud af, hvor mange tilladelser der i øjeblikket er tilgængelige i Semaphore ved hjælp af metoden int availablePermits(). Du kan også forsøge at få en tilladelse ved hjælp af metoden boolean tryAcquire(), som returnerer true, hvis en tilladelse blev opnået, og false, hvis ikke.
Main.java
1234567891011121314151617181920212223242526272829303132333435363738394041package 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()); } } } }
Med andre ord er en Semaphore nyttig, når der skal gives begrænset samtidig adgang til et bestemt kodeafsnit. Den eneste ulempe er risikoen for deadlock, hvis tråde blokeres i forkert rækkefølge.
Lad os nu gå videre til den næste synchroniseringsmekanisme, som er endnu nemmere at anvende, men vil være 100 procent værdifuld for dine behov.
CyclicBarrier
Barrier i Java repræsenteres af klassen java.util.concurrent.CyclicBarrier. De vigtigste metoder i CyclicBarrier omfatter:
Konstruktører CyclicBarrier
CyclicBarrier(int parties): Konstruktør, der opretter en barrier, som blokerer tråde, indtil et bestemt antal tråde (parties) ankommer.
Main.java
1CyclicBarrier cyclicBarrier = new CyclicBarrier(10);
CyclicBarrier(int parties, Runnable barrierAction): Konstruktør, der opretter en barriere med et angivet antal parter og en handling (barrierAction), som udføres, når alle parter ankommer til barrieren.
Main.java
1234567Runnable 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 CyclicBarrier
Hovedmetoden await(), som bruges som en barriere og ikke lader tråden fortsætte, før alle tråde når denne metode. Returnerer et sekvens-nummer, der angiver rækkefølgen for deltagernes ankomst.
Main.java
1234567891011121314151617181920212223242526272829303132333435363738394041424344package 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 ske, at ikke alle tråde vil nå barrieren, og programmet vil gå i stå. Til dette formål anvendes metoden int await(long timeout, TimeUnit unit), som ligner await(), men med timeout. Hvis timeout udløber, før alle deltagere ankommer, genererer metoden en TimeoutException-undtagelse.
Det er også muligt at finde ud af antallet af deltagere, der kræves for at fuldføre barrieren med int getParties() samt den lignende metode int getNumberWaiting(), som returnerer antallet af deltagere, der aktuelt venter ved barrieren.
Main.java
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849package 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å muligt at kontrollere, om barrieren er blevet ødelagt, hvis en af trådene bliver afbrudt, eller hvis ventetiden er udløbet, ved at bruge boolean isBroken() metoden. Hvis den er blevet ødelagt, kan du bruge void reset() metoden, som simpelt gendanner barrieren.
Main.java
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(); }
Det skal tages i betragtning, at nogle tråde muligvis ikke når barrieren på grund af en fejl eller andet, og det er derfor tydeligt, at barrieren ikke vil tillade de tråde, der i øjeblikket venter ved barrieren, at fortsætte.
Tak for dine kommentarer!
Spørg AI
Spørg AI
Spørg om hvad som helst eller prøv et af de foreslåede spørgsmål for at starte vores chat
Can you explain the main differences between Semaphore and CyclicBarrier?
How do I decide when to use Semaphore versus CyclicBarrier in my program?
Can you provide examples of real-world scenarios for each synchronization mechanism?
Awesome!
Completion rate improved to 3.33
Semafor og Barriere
Stryg for at vise menuen
I multitrådede programmer er det ofte nødvendigt at kontrollere adgangen til ressourcer eller synkronisere trådenes udførelse. Semaphore og Barrier er højniveau synkroniseringsmekanismer, der hjælper med at håndtere disse udfordringer.
I dag vil vi undersøge hver af disse mekanismer i rækkefølge og forstå deres forskelle. Lad os begynde med Semaphore.
Semaphore i Java implementeres gennem klassen java.util.concurrent.Semaphore.
Konstruktører
Semaphore(int permits): Konstruktør, der opretter en semaphore med et bestemt antal tilladelser. Tilladelserne repræsenterer antallet af adgange til den delte ressource.
Main.java
1Semaphore semaphore = new Semaphore(20);
Semaphore(int permits, boolean fair): Konstruktør, der sikrer først-til-mølle-princippet.
Main.java
1Semaphore semaphore = new Semaphore(20, true);
Hvis fair er sat til true, vil semaphore tildele tilladelser i først-ind-først-ud (FIFO) rækkefølge, hvilket kan hjælpe med at undgå sult. Standard - false.
Hovedmetoder
Metoden acquire() anmoder om en enkelt tilladelse. Hvis en tilladelse er tilgængelig, tildeles den straks; ellers bliver tråden blokeret, indtil en tilladelse bliver tilgængelig. Når en opgave er fuldført, bruges metoden release() til at frigive tilladelsen og returnere den til semaphore. Hvis andre tråde ventede på en tilladelse, vil én af dem blive afblokeret.
Forestil dig en parkeringsplads med et begrænset antal pladser. semaphore fungerer som en kontrolinstans, der holder styr på de tilgængelige pladser og afviser adgang, når pladsen er fuld.
Main.java
1234567891011121314151617181920212223242526272829303132package 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å finde ud af, hvor mange tilladelser der i øjeblikket er tilgængelige i Semaphore ved hjælp af metoden int availablePermits(). Du kan også forsøge at få en tilladelse ved hjælp af metoden boolean tryAcquire(), som returnerer true, hvis en tilladelse blev opnået, og false, hvis ikke.
Main.java
1234567891011121314151617181920212223242526272829303132333435363738394041package 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()); } } } }
Med andre ord er en Semaphore nyttig, når der skal gives begrænset samtidig adgang til et bestemt kodeafsnit. Den eneste ulempe er risikoen for deadlock, hvis tråde blokeres i forkert rækkefølge.
Lad os nu gå videre til den næste synchroniseringsmekanisme, som er endnu nemmere at anvende, men vil være 100 procent værdifuld for dine behov.
CyclicBarrier
Barrier i Java repræsenteres af klassen java.util.concurrent.CyclicBarrier. De vigtigste metoder i CyclicBarrier omfatter:
Konstruktører CyclicBarrier
CyclicBarrier(int parties): Konstruktør, der opretter en barrier, som blokerer tråde, indtil et bestemt antal tråde (parties) ankommer.
Main.java
1CyclicBarrier cyclicBarrier = new CyclicBarrier(10);
CyclicBarrier(int parties, Runnable barrierAction): Konstruktør, der opretter en barriere med et angivet antal parter og en handling (barrierAction), som udføres, når alle parter ankommer til barrieren.
Main.java
1234567Runnable 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 CyclicBarrier
Hovedmetoden await(), som bruges som en barriere og ikke lader tråden fortsætte, før alle tråde når denne metode. Returnerer et sekvens-nummer, der angiver rækkefølgen for deltagernes ankomst.
Main.java
1234567891011121314151617181920212223242526272829303132333435363738394041424344package 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 ske, at ikke alle tråde vil nå barrieren, og programmet vil gå i stå. Til dette formål anvendes metoden int await(long timeout, TimeUnit unit), som ligner await(), men med timeout. Hvis timeout udløber, før alle deltagere ankommer, genererer metoden en TimeoutException-undtagelse.
Det er også muligt at finde ud af antallet af deltagere, der kræves for at fuldføre barrieren med int getParties() samt den lignende metode int getNumberWaiting(), som returnerer antallet af deltagere, der aktuelt venter ved barrieren.
Main.java
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849package 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å muligt at kontrollere, om barrieren er blevet ødelagt, hvis en af trådene bliver afbrudt, eller hvis ventetiden er udløbet, ved at bruge boolean isBroken() metoden. Hvis den er blevet ødelagt, kan du bruge void reset() metoden, som simpelt gendanner barrieren.
Main.java
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(); }
Det skal tages i betragtning, at nogle tråde muligvis ikke når barrieren på grund af en fejl eller andet, og det er derfor tydeligt, at barrieren ikke vil tillade de tråde, der i øjeblikket venter ved barrieren, at fortsætte.
Tak for dine kommentarer!