Cosa sono mutex e semaforo in Java? Qual è la differenza principale?


Risposte:


115

Il semaforo può essere contato, mentre il mutex può contare solo fino a 1.

Supponiamo di avere un thread in esecuzione che accetta le connessioni client. Questo thread può gestire 10 client contemporaneamente. Quindi ogni nuovo client imposta il semaforo finché non raggiunge 10. Quando il semaforo ha 10 flag, il thread non accetterà nuove connessioni

I mutex sono solitamente usati per proteggere le cose. Supponiamo che i tuoi 10 client possano accedere a più parti del sistema. Quindi puoi proteggere una parte del sistema con un mutex così quando 1 client è connesso a quel sottosistema, nessun altro dovrebbe avere accesso. Puoi usare un semaforo anche per questo scopo. Un mutex è un "semaforo di mutua esclusione" .


4
Questo non è del tutto vero. Lo stesso thread può entrare nello stesso mutex più di una volta, quindi è necessario mantenere un conteggio per garantire che le voci `e uscite siano bilanciate.
finnw

1
@finnw, in generale ci sono due tipi di mutex, ricorsivi e non ricorsivi. Java per impostazione predefinita utilizza il tipo ricorsivo?
edA-qa mort-ora-y

2
@ edA-qa mort-ora-y, il termine "Mutex" non viene utilizzato nelle specifiche Java VM o API, quindi presumo che si riferisca al monitor integrato in ogni oggetto, che è anche simile all'oggetto Win32 chiamato Mutex . Lo stesso vale per un file ReentrantLock. Tutti questi sono ricorsivi. Non sono a conoscenza di alcun esempio "reale" di mutex non ricorsivi (li ho visti solo nei libri di testo), quindi non li ho presi in considerazione.
finnw

2
I mutex non ricorsivi possono essere implementati usando un semaforo con conteggio uno. Questo può essere utile se vuoi prevenire le chiamate ricorsive. Questo ha usi pratici, l'ho usato personalmente in grandi progetti per rilevare loop nel codice di inizializzazione (A inizializza B che tenta di inizializzare di nuovo A).
Alexander Torstling

1
Nello standard C ++ 11 (C ++ 0x), mutex non è ricorsivo. Forniscono anche un "recursive_mutex" separato per coloro che ne hanno bisogno. So che stiamo parlando di Java qui, ma ora molti di noi codificano in più lingue.
Aditya Kumar Pandey

139

Purtroppo tutti hanno perso la differenza più importante tra il semaforo e il mutex; il concetto di " proprietà ".

I semafori non hanno la nozione di proprietà, questo significa che qualsiasi thread può rilasciare un semaforo (questo può portare a molti problemi di per sé ma può aiutare con il "rilevamento della morte"). Mentre un mutex ha il concetto di proprietà (cioè puoi rilasciare solo un mutex che hai acquisito).
La proprietà è incredibilmente importante per la programmazione sicura di sistemi concorrenti. Consiglierei sempre di usare mutex invece di un semaforo (ma ci sono implicazioni sulle prestazioni).

I mutex possono anche supportare l'ereditarietà delle priorità (che può aiutare con il problema dell'inversione delle priorità) e la ricorsione (eliminando un tipo di deadlock).

Va anche sottolineato che esistono semafori "binari" e semafori "conteggio / generali". Il semaforo di Java è un semaforo di conteggio e quindi consente di inizializzarlo con un valore maggiore di uno (mentre, come sottolineato, un mutex può contare solo un conteggio concettuale di uno). L'utilità di questo è stata evidenziata in altri post.

Quindi, per riassumere, a meno che tu non abbia più risorse da gestire, consiglierei sempre il mutex sul semaforo.


1
La risposta di Feabhas è piuttosto importante: il mutex controlla il thread che tenta di rilasciare il mutex in realtà lo possiede. Ho avuto questa domanda come intervista, quindi vale la pena cercare di ricordarla.
andrew pate

40

Il mutex è fondamentalmente l'esclusione reciproca. Solo un thread alla volta può acquisire la risorsa. Quando un thread acquisisce la risorsa, a nessun altro thread è consentito acquisire la risorsa fino a quando il thread proprietario della risorsa non rilascia. Tutti i thread in attesa di acquisire la risorsa verrebbero bloccati.

Il semaforo viene utilizzato per controllare il numero di thread in esecuzione. Ci sarà un insieme fisso di risorse. Il conteggio delle risorse verrà diminuito ogni volta che un thread possiede lo stesso. Quando il conteggio del semaforo raggiunge 0, nessun altro thread può acquisire la risorsa. I thread vengono bloccati fino a quando altri thread possiedono il rilascio delle risorse.

In breve, la differenza principale è quanti thread sono autorizzati ad acquisire la risorsa contemporaneamente?

  • Mutex: il suo ONE.
  • Semaforo: è DEFINED_COUNT, (tanti quanti sono i semafori)

8

Un mutex viene utilizzato per l'accesso seriale a una risorsa mentre un semaforo limita l'accesso a una risorsa fino a un numero impostato. Puoi pensare a un mutex come un semaforo con un conteggio degli accessi pari a 1. Qualunque sia il tuo conteggio del semaforo, i thread possono accedere alla risorsa prima che la risorsa venga bloccata.



3

Un mutex è spesso noto come semaforo binario. Sebbene un semaforo possa essere creato con qualsiasi conteggio diverso da zero, un mutex è concettualmente un semaforo con un conteggio superiore di 1.



1

Semaforo :

Un semaforo di conteggio. Concettualmente, un semaforo mantiene una serie di permessi. Ogni acquire()blocco se necessario fino a quando non è disponibile un permesso, quindi lo prende. Ciascuno release()aggiunge un permesso, rilasciando potenzialmente un acquirente con blocco. Tuttavia, non viene utilizzato alcun oggetto permesso effettivo; il semaforo tiene solo un conteggio del numero disponibile e agisce di conseguenza.

I semafori sono spesso usati per limitare il numero di thread che possono accedere ad alcune risorse (fisiche o logiche)

Java non ha l'API Mutex incorporata. Ma può essere implementato come semaforo binario.

Un semaforo inizializzato a uno, e utilizzato in modo tale da avere al massimo un permesso disponibile, può fungere da blocco di mutua esclusione. Questo è più comunemente noto come semaforo binario, perché ha solo due stati: un permesso disponibile o zero permessi disponibili.

Quando viene utilizzato in questo modo, il semaforo binario ha la proprietà (a differenza di molte implementazioni di Lock), che il "lock" può essere rilasciato da un thread diverso dal proprietario (poiché i semafori non hanno la nozione di proprietà) . Questo può essere utile in alcuni contesti specializzati, come il ripristino dei deadlock.

Quindi differenze chiave tra Semaphore e Mutex:

  1. Il semaforo limita il numero di thread per accedere a una risorsa tramite i permessi. Mutex consente a un solo thread di accedere alla risorsa.

  2. Nessun thread possiede il semaforo. I thread possono aggiornare il numero di permessi chiamando acquire()e release()metodi. I mutex dovrebbero essere sbloccati solo dal thread che tiene il blocco.

  3. Quando si usa un mutex con variabili di condizione, c'è un bracketing implicito: è chiaro quale parte del programma è protetta . Questo non è necessariamente il caso di un semaforo, che potrebbe essere chiamato il punto di partenza della programmazione concorrente: è potente ma troppo facile da usare in modo non strutturato e indeterminato.


0

Mutex è un semaforo binario. Deve essere inizializzato con 1, in modo che il principio First Come First Serve sia soddisfatto. Questo ci porta all'altra proprietà speciale di ogni mutex: colui che ha abbassato , deve essere quello che ha alzato . Ergo abbiamo ottenuto l'esclusione reciproca su qualche risorsa.

Ora puoi vedere che un mutex è un caso speciale di semaforo generale.


0

L'oggetto della sincronizzazione Semaphoreimplementa un semaforo classico. Un semaforo controlla l'accesso a una risorsa condivisa da un contatore. Se il contatore è maggiore di zero, l'accesso è concesso; Se è zero, l'accesso è negato. Il contatore conta le autorizzazioni che consentono l'accesso alla risorsa condivisa. Quindi, per accedere alla risorsa, un thread deve ricevere l'autorizzazione dal semaforo. In generale, per utilizzare un semaforo, il thread che vuole accedere alla risorsa condivisa cerca di acquisire un permesso. Se il conteggio del semaforo è maggiore di zero, il thread acquisisce un permesso e il conteggio del semaforo viene diminuito. Altrimenti il ​​thread è bloccato finché non può ottenere un'autorizzazione. Quando il thread non ha più bisogno di accedere alla risorsa condivisa, rilascia l'autorizzazione, quindi il conteggio del semaforo aumenta. Se c'è un altro thread in attesa di un permesso, acquisisce un permesso in quel momento. La classe Semaphore di Java implementa questo meccanismo.

Semaphore ha due builder:

Semaphore(int num)
Semaphore(int num, boolean come)

num specifica il conteggio iniziale del permesso. Quindi num specifica il numero di thread che possono accedere a una risorsa condivisa in un dato momento. Se num è uno, può accedere alla risorsa un thread alla volta. Impostando venire come vero, si può garantire che i fili si è in attesa sono concessi il permesso nell'ordine in cui sono richiesti.


0

Metti a confronto l'incomparabile, tecnicamente non c'è differenza tra un semaforo e un mutex, non ha senso. Mutex è solo un nome significativo come qualsiasi nome nella logica dell'applicazione, significa che si inizializza un semaforo a "1", viene utilizzato generalmente per proteggere una risorsa o una variabile protetta per garantire l'esclusione reciproca.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.