V Javě používáme semafor při synchronizaci vláken. Používá se k řízení přístupu ke sdílenému prostředku, který využívá proměnnou čítače. Java také poskytuje třídu Semafor, která obsahuje konstruktory a různé metody pro řízení přístupu nad sdíleným prostředkem. Probereme ji později v této části.
Než budeme pokračovat v této části, nejprve pochopíme, co je to semafor, typy semaforu, jak funguje a jak implementovat semafor. Poté, co se o něm vše dozvíme, přejdeme k programům pro semafory v Javě.
- Co je to semafor?
- Charakteristika semaforu
- Fungování semaforu
- Typy semaforů
- Počítací semafory
- Ohraničené semafory
- Timed Semaphores
- Binární semafory
- Semaphore v Javě
- Třída Java Semaphore
- Semaphore(int permits)
- Semaphore(int permits, boolean fair)
- Metody třídy Semafor
- Použití semaforu jako zámku
- Poznámka: Při spuštění výše uvedeného programu dostaneme pokaždé jiný výstup. Váš výstup se tedy může lišit od výstupu uvedeného výše.
- Příklad semaforu Java
Co je to semafor?
Semafor se používá k omezení počtu vláken, která chtějí přistupovat ke sdílenému prostředku. Jinými slovy se jedná o nezápornou proměnnou, která je sdílena mezi vlákny známými jako čítač. Nastavuje limit počtu vláken. Mechanismus, kdy vlákno čeká na semafor, může být signalizován ostatními vlákny.
- Pokud je čítač > 0, je přístup ke sdíleným prostředkům umožněn.
- Pokud je čítač = 0, je přístup ke sdíleným prostředkům odepřen.
Zkrátka čítač neustále sleduje počet oprávnění, která ke sdílenému prostředku udělil. Semafor tedy uděluje vláknům oprávnění ke sdílení prostředku.
Charakteristika semaforu
Semafor má následující vlastnosti:
- Zajišťuje synchronizaci mezi vlákny.
- Snižuje úroveň synchronizace. Poskytuje tedy nízkoúrovňový mechanismus synchronizace.
- Semafor neobsahuje zápornou hodnotu. Udržuje hodnotu, která může být buď větší než nula, nebo rovna nule.
- Semafor můžeme implementovat pomocí testovací operace a přerušení a pro jeho spuštění používáme deskriptory souborů.
Fungování semaforu
Semafor řídí sdílené prostředky prostřednictvím proměnné čítače. Čítač je nezáporná hodnota. Obsahuje buď hodnotu větší než 0, nebo rovnou 0.
- Pokud čítač > 0, vlákno získá povolení k přístupu ke sdílenému prostředku a hodnota čítače se sníží o 1.
- V opačném případě bude vlákno blokováno, dokud se nepodaří získat povolení.
- Když je provádění vlákna ukončeno, pak není prostředek potřeba a vlákno jej uvolní. Po uvolnění prostředku se hodnota čítače zvýší o 1.
- Pokud na získání prostředku čeká jiné vlákno, vlákno v té době získá povolení.
- Pokud je čítač = 0, vlákno nedostane povolení k přístupu ke sdílenému prostředku.
Pochopíme fungování semaforu pomocí vývojového diagramu.
Typy semaforů
Existují čtyři typy semaforů, které jsou následující:
- Semafory počítací
- Semafory omezené
- Semafory časové
- Semafory binární
Probereme jeden po druhém podrobněji.
Počítací semafory
Počítací semafory se používají k řešení situace, kdy chce v kritické sekci vykonávat více procesů současně. Proto k překonání tohoto problému používáme počítací semafory. Uvažujme například následující úryvek kódu.
Podívejme se na implementaci počítacích semaforů.
CountingSemaphoresExample.java
Ohraničené semafory
Pomocí omezených semaforů můžeme nastavit horní mez. Používá se místo počítacích semaforů, protože počítací semafory neobsahují žádnou hodnotu horní hranice. Hodnota horní hranice označuje, kolik signálů může uložit. Uvažujme například následující úryvek kódu.
Podívejme se na implementaci omezeného semaforu.
BoundedSemaphoresExample.java
Timed Semaphores
Timed semafory umožňují běh vlákna po určitou dobu. Po uplynutí určité doby se časovač vynuluje a uvolní všechna ostatní povolení.
Podívejme se na implementaci časovaných semaforů.
TimedSemaphoresExample.java
Binární semafory
Binární semafory jsou stejné jako počítací semafory. Nezapomeňte však, že přijímá pouze binární hodnoty buď 0, nebo 1. Jeho implementace je ve srovnání s ostatními semafory snadná. Pokud je hodnota 1, je signální operace úspěšná, v opačném případě selže.
Podívejme se na implementaci binárních semaforů.
BinarySemaphoresExample.java
Semaphore v Javě
V Javě je to konstrukce pro synchronizaci vláken. Konstrukce používá proměnnou známou jako čítač, která řídí přístup nad sdíleným prostředkem. Jedná se o typ proměnné, která se používá ke správě souběžných procesů a také k jejich synchronizaci. Používá se také k zamezení závodních podmínek. Omezuje počet vláken pro přístup ke sdílenému prostředku.
Například můžeme omezit přístup k souboru na maximálně 10 spojení současně.
Třída Java Semaphore
Java poskytuje třídu Semaphore pro implementaci mechanismu semaforů. Patří do balíčku java.util.concurrent. Implementuje rozhraní Serializable. Proto není nutná ruční implementace.
Třída Semafor poskytuje následující dva konstruktory:
- Semaphore(int permits)
- Semaphore(int permits, boolean fair)
Semaphore(int permits)
Vytváří Semafor a jako argument analyzuje počet permitů (počáteční počet dostupných permitů). Určuje počet vláken, která mohou v daném okamžiku sdílet prostředek. Hodnota permits může být záporná. V takovém případě musí dojít k uvolnění předtím, než bude uděleno nějaké získání.
Syntaxe:
Semaphore(int permits, boolean fair)
Vytvoří Semafor s daným počtem permitů a daným nastavením fairness.
Syntaxe:
Parsuje dva parametry:
- permits: Hodnota permitů může být záporná. V takovém případě musí dojít k uvolnění dříve, než bude uděleno jakékoliv acquires.
- fair: Pokud nastavíme hodnotu na true, semafor zaručí FIFO vláknům v pořadí, v jakém jsou požadována, false Ve výchozím nastavení všechna vlákna, která čekají na zdroj, udělí permit v nedefinovaném pořadí.
Metody třídy Semafor
Třída poskytuje následující metody:
acquire() Metoda: Metoda získá povolení ze semaforu, přičemž blokuje, dokud není k dispozici, nebo dokud není vlákno přerušeno. Snižuje počet dostupných povolení o 1.
Pokud pro aktuální vlákno není k dispozici žádné povolení, vlákno se pro účely plánování vláken stane zakázaným. Aktuální vlákno přejde do neaktivního stavu, dokud se nestane jedna ze dvou věcí:
- Pokud jiné vlákno vyvolá metodu release() pro uvolnění zdroje, pak aktuální vlákno získá povolení.
- Pokud jiné vlákno přeruší aktuální vlákno.
Vyhodí InterruptedException, pokud je aktuální vlákno přerušeno. Metoda nevrací žádnou hodnotu.
Syntaxe:
release() Metoda: Uvolní povolení a vrátí jej do semaforu. Zvyšuje počet dostupných povolení o 1. Pokud se vlákno pokusí získat povolení, udělí semafor povolení k získání prostředku, který byl právě uvolněn jinými vlákny. Dále je toto vlákno bráno v úvahu pro účely plánování vláken.
Syntaxe:
availablePermits() Metoda: Metoda vrací počet dostupných povolení v semaforu pro přidělení prostředku. Obvykle se používá pro účely ladění a testování.
Syntaxe:
Pochopme výše uvedené metody na jednoduchém příkladu.
Použití semaforu jako zámku
Java nám umožňuje použít semafor jako zámek. To znamená, že uzamkne přístup k prostředku. Každé vlákno, které chce přistupovat k uzamčenému prostředku, musí před přístupem k prostředku zavolat metodu acquire(), aby získalo zámek. Po dokončení úlohy musí vlákno zámek uvolnit voláním metody release(). Nezapomeňte nastavit horní hranici na hodnotu 1. Uvažujme například následující úryvek kódu:
Podívejme se na příklad semaforu a použití semaforu jako zámku.
SemaphoreAsLock.java
Výstup:
Poznámka: Při spuštění výše uvedeného programu dostaneme pokaždé jiný výstup. Váš výstup se tedy může lišit od výstupu uvedeného výše.
Příklad semaforu Java
Pochopíme mechanismus semaforu prostřednictvím programu v jazyce Java. V následujícím příkladu jsme vytvořili konstruktor třídy Semafor s počáteční hodnotou povolení 3.
SemaphoreExample.java
Výstup:
.