Un ReentrantLock non è strutturato , a differenza dei synchronized
costrutti, ovvero non è necessario utilizzare una struttura a blocchi per bloccare e può persino tenere un blocco tra i metodi. Un esempio:
private ReentrantLock lock;
public void foo() {
...
lock.lock();
...
}
public void bar() {
...
lock.unlock();
...
}
Tale flusso è impossibile da rappresentare tramite un singolo monitor in un synchronized
costrutto.
A parte ciò, ReentrantLock
supporta il polling dei blocchi e il blocco interrompibile attende il supporto del timeout . ReentrantLock
supporta anche la politica di equità configurabile , consentendo una pianificazione dei thread più flessibile.
Il costruttore per questa classe accetta un parametro di equità opzionale . Se impostato true
, in contesa, i blocchi favoriscono l'accesso al thread più lungo in attesa. In caso contrario, questo blocco non garantisce alcun ordine di accesso particolare. I programmi che usano blocchi equi a cui accedono molti thread possono mostrare un throughput complessivo inferiore (cioè sono più lenti; spesso molto più lenti) rispetto a quelli che usano l'impostazione predefinita, ma hanno varianze minori in tempi per ottenere blocchi e garantire la mancanza di fame. Si noti tuttavia che l'equità dei blocchi non garantisce l'equità della programmazione dei thread. Pertanto, uno dei tanti thread che usano un fair lock può ottenerlo più volte in successione mentre altri thread attivi non stanno procedendo e attualmente non tengono il lock. Si noti inoltre che il senza orariotryLock
il metodo non rispetta l'impostazione dell'equità. Avrà successo se il blocco è disponibile anche se altri thread sono in attesa.
ReentrantLock
può anche essere più scalabile , con prestazioni molto migliori in contese più elevate. Puoi leggere di più su questo qui .
Questa richiesta è stata contestata, tuttavia; vedi il seguente commento:
Nel test di blocco rientrante, ogni volta viene creato un nuovo blocco, quindi non esiste un blocco esclusivo e i dati risultanti non sono validi. Inoltre, il collegamento IBM non offre alcun codice sorgente per il benchmark sottostante, quindi è impossibile stabilire se il test sia stato condotto correttamente.
Quando dovresti usare ReentrantLock
s? Secondo l'articolo di DeveloperWorks ...
La risposta è piuttosto semplice: usala quando in realtà hai bisogno di qualcosa che synchronized
non fornisca , come le attese di blocco temporizzate, le attese di blocco interrompibili, i blocchi non strutturati a blocchi, le variabili a più condizioni o il polling dei blocchi. ReentrantLock
ha anche vantaggi di scalabilità e dovresti usarlo se hai effettivamente una situazione che presenta un'elevata contesa, ma ricorda che la stragrande maggioranza dei synchronized
blocchi non mostra quasi mai alcuna contesa, per non parlare dell'elevata contesa. Consiglierei di sviluppare con la sincronizzazione fino a quando la sincronizzazione non si sarà dimostrata inadeguata, anziché semplicemente supporre che "le prestazioni saranno migliori" se si utilizzaReentrantLock
. Ricorda, questi sono strumenti avanzati per utenti esperti. (E gli utenti veramente avanzati tendono a preferire gli strumenti più semplici che riescono a trovare fino a quando non sono convinti che gli strumenti semplici siano inadeguati.) Come sempre, prima fai la cosa giusta e poi preoccupati se devi farlo più velocemente.