Semafor och Barriär
I multitrådade program är det ofta nödvändigt att kontrollera åtkomst till resurser eller synkronisera trådens exekvering. Semaphore och Barrier är hög-nivå synkroniseringsmekanismer som hjälper till att hantera dessa utmaningar.
Idag kommer vi att utforska var och en av dessa mekanismer i tur och ordning och förstå deras skillnader. Vi börjar med Semaphore.
Semaphore i Java implementeras genom klassen java.util.concurrent.Semaphore.
Konstruktorer
Semaphore(int permits): Konstruktor som skapar en semaphore med ett visst antal tillstånd. Tillstånden representerar antalet åtkomster till den delade resursen.
Main.java
1Semaphore semaphore = new Semaphore(20);
Semaphore(int permits, boolean fair): Konstruktor som tillhandahåller först till kvarn-principen, först betjänad-lösning.
Main.java
1Semaphore semaphore = new Semaphore(20, true);
Om fair är satt till true, kommer semaphore att bevilja tillstånd i först in, först ut (FIFO)-ordning, vilket kan hjälpa till att undvika svält. Standardvärde - false.
Huvudsakliga metoder
Metoden acquire() begär ett enskilt tillstånd. Om ett tillstånd är tillgängligt beviljas det omedelbart; annars blockeras tråden tills ett tillstånd blir tillgängligt. När en uppgift är slutförd används metoden release() för att släppa tillståndet och återlämna det till semaphore. Om andra trådar väntade på ett tillstånd kommer en av dem att avblockeras.
Föreställ dig en parkeringsplats med ett begränsat antal platser. semaphore fungerar som en kontrollant som håller reda på tillgängliga platser och nekar tillgång när platsen är full.
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 också ta reda på hur många tillstånd som för närvarande är tillgängliga i Semaphore med metoden int availablePermits(). Du kan även försöka hämta ett tillstånd med metoden boolean tryAcquire(), som returnerar true om ett tillstånd erhölls och false om inte.
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 andra ord är en Semaphore användbar när du behöver tillåta begränsad samtidig åtkomst till ett specifikt kodavsnitt. Den enda nackdelen är risken för deadlock om trådar blockeras i fel ordning.
Nu går vi vidare till nästa synkroniseringsmekanism som är ännu enklare att använda men kommer att vara hundra procent värdefull för dina behov.
CyclicBarrier
Barrier i Java representeras av klassen java.util.concurrent.CyclicBarrier. De huvudsakliga metoderna för CyclicBarrier inkluderar:
Konstruktorer CyclicBarrier
CyclicBarrier(int parties): Konstruktor som skapar en barriär som blockerar trådar tills ett visst antal trådar (parties) anländer.
Main.java
1CyclicBarrier cyclicBarrier = new CyclicBarrier(10);
CyclicBarrier(int parties, Runnable barrierAction): Konstruktor som skapar en barriär med ett angivet antal parter och en åtgärd (barrierAction) som utförs när alla parter når barriären.
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
Huvudmetoden await() används som en barriär och tillåter inte tråden att fortsätta förrän alla trådar når denna metod. Returnerar ett sekvensnummer som anger deltagarnas ankomstordning.
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 inträffa att inte alla trådar når barriären och programmet hänger sig. För detta ändamål används metoden await(long timeout, TimeUnit unit), som liknar await(), men med tidsgräns. Om tidsgränsen överskrids innan alla deltagare anländer, genererar metoden ett undantag av typen TimeoutException.
Det går även att ta reda på antalet deltagare som krävs för att slutföra barriären med int getParties() samt den liknande metoden int getNumberWaiting() som returnerar antalet deltagare som för närvarande väntar vid barriären.
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 är också möjligt att kontrollera om barriären har blivit förstörd om en av trådarna avbryts eller om väntetiden har gått ut genom att använda metoden boolean isBroken(). Om den har brutits kan du använda metoden void reset() som återställer barriären.
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 bör beaktas att vissa flöden kanske inte når barriären på grund av ett fel eller något annat, och då är det tydligt att barriären inte kommer att släppa igenom de flöden som för närvarande väntar vid barriären.
Tack för dina kommentarer!
Fråga AI
Fråga AI
Fråga vad du vill eller prova någon av de föreslagna frågorna för att starta vårt samtal
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 och Barriär
Svep för att visa menyn
I multitrådade program är det ofta nödvändigt att kontrollera åtkomst till resurser eller synkronisera trådens exekvering. Semaphore och Barrier är hög-nivå synkroniseringsmekanismer som hjälper till att hantera dessa utmaningar.
Idag kommer vi att utforska var och en av dessa mekanismer i tur och ordning och förstå deras skillnader. Vi börjar med Semaphore.
Semaphore i Java implementeras genom klassen java.util.concurrent.Semaphore.
Konstruktorer
Semaphore(int permits): Konstruktor som skapar en semaphore med ett visst antal tillstånd. Tillstånden representerar antalet åtkomster till den delade resursen.
Main.java
1Semaphore semaphore = new Semaphore(20);
Semaphore(int permits, boolean fair): Konstruktor som tillhandahåller först till kvarn-principen, först betjänad-lösning.
Main.java
1Semaphore semaphore = new Semaphore(20, true);
Om fair är satt till true, kommer semaphore att bevilja tillstånd i först in, först ut (FIFO)-ordning, vilket kan hjälpa till att undvika svält. Standardvärde - false.
Huvudsakliga metoder
Metoden acquire() begär ett enskilt tillstånd. Om ett tillstånd är tillgängligt beviljas det omedelbart; annars blockeras tråden tills ett tillstånd blir tillgängligt. När en uppgift är slutförd används metoden release() för att släppa tillståndet och återlämna det till semaphore. Om andra trådar väntade på ett tillstånd kommer en av dem att avblockeras.
Föreställ dig en parkeringsplats med ett begränsat antal platser. semaphore fungerar som en kontrollant som håller reda på tillgängliga platser och nekar tillgång när platsen är full.
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 också ta reda på hur många tillstånd som för närvarande är tillgängliga i Semaphore med metoden int availablePermits(). Du kan även försöka hämta ett tillstånd med metoden boolean tryAcquire(), som returnerar true om ett tillstånd erhölls och false om inte.
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 andra ord är en Semaphore användbar när du behöver tillåta begränsad samtidig åtkomst till ett specifikt kodavsnitt. Den enda nackdelen är risken för deadlock om trådar blockeras i fel ordning.
Nu går vi vidare till nästa synkroniseringsmekanism som är ännu enklare att använda men kommer att vara hundra procent värdefull för dina behov.
CyclicBarrier
Barrier i Java representeras av klassen java.util.concurrent.CyclicBarrier. De huvudsakliga metoderna för CyclicBarrier inkluderar:
Konstruktorer CyclicBarrier
CyclicBarrier(int parties): Konstruktor som skapar en barriär som blockerar trådar tills ett visst antal trådar (parties) anländer.
Main.java
1CyclicBarrier cyclicBarrier = new CyclicBarrier(10);
CyclicBarrier(int parties, Runnable barrierAction): Konstruktor som skapar en barriär med ett angivet antal parter och en åtgärd (barrierAction) som utförs när alla parter når barriären.
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
Huvudmetoden await() används som en barriär och tillåter inte tråden att fortsätta förrän alla trådar når denna metod. Returnerar ett sekvensnummer som anger deltagarnas ankomstordning.
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 inträffa att inte alla trådar når barriären och programmet hänger sig. För detta ändamål används metoden await(long timeout, TimeUnit unit), som liknar await(), men med tidsgräns. Om tidsgränsen överskrids innan alla deltagare anländer, genererar metoden ett undantag av typen TimeoutException.
Det går även att ta reda på antalet deltagare som krävs för att slutföra barriären med int getParties() samt den liknande metoden int getNumberWaiting() som returnerar antalet deltagare som för närvarande väntar vid barriären.
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 är också möjligt att kontrollera om barriären har blivit förstörd om en av trådarna avbryts eller om väntetiden har gått ut genom att använda metoden boolean isBroken(). Om den har brutits kan du använda metoden void reset() som återställer barriären.
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 bör beaktas att vissa flöden kanske inte når barriären på grund av ett fel eller något annat, och då är det tydligt att barriären inte kommer att släppa igenom de flöden som för närvarande väntar vid barriären.
Tack för dina kommentarer!