2012-06-20 17 views
14

Qual è il modo migliore per impedire l'aggiornamento simultaneo di un record in un set di valori-chiave senza bloccare l'intero set? Semanticamente, sto cercando qualche tipo di blocco da una chiave (idealmente, implementazione Java, ma non necessariamente):Come acquisire un blocco tramite una chiave

interface LockByKey { 
    void lock(String key); // acquire an exclusive lock for a key 
    void unlock(String key); // release lock for a key 
} 

Questo blocco ha lo scopo di sincronizzare un accesso a un archivio remoto, in modo un po 'di raccolta Java sincronizzato non è un'opzione.

+1

Questo ha molto a che fare con la sincronizzazione dell'accesso al negozio remoto. Non sono sicuro se questa domanda possa essere risolta senza sapere di più su come gestisci la concorrenza da remoto. –

+0

Dai un'occhiata a http://stackoverflow.com/a/28347825/704335. – Timmos

+0

È possibile utilizzare: http://stackoverflow.com/a/28723518/1183010 –

risposta

25

Guava ha qualcosa come questo che viene rilasciato in 13.0; puoi farlo uscire dalla TESTA se vuoi.

Striped<Lock> assegna più o meno un numero specifico di blocchi e assegna quindi le stringhe ai blocchi in base al loro codice hash. L'API sembra più o meno come

Striped<Lock> locks = Striped.lock(stripes); 
Lock l = locks.get(string); 
l.lock(); 
try { 
    // do stuff 
} finally { 
    l.unlock(); 
} 

Più o meno, il numero di strisce controllabile permette di scambiare la concorrenza contro l'utilizzo della memoria, perché l'allocazione di un blocco completo per ogni tasto stringa può ottenere costosi; in sostanza, si ottiene una contesa di blocco solo quando si verificano collisioni hash, che sono (prevedibilmente) rare.

(Disclosure:. Contribuisco a Guava)

+0

la memoria associata ai vecchi blocchi viene ripulita? come se fossero conservati in una WeakHashMap. –

+2

Lo fa se si utilizza il metodo factory per generare blocchi deboli. –

+1

@Jose Martinez: no, non pulisce nulla, non deve, funziona su un principio diverso. Prendiamo ad esempio 'Striped.lock (1024)', che crea una semplice matrice Lock [1024], inizializzata avidamente con 1024 oggetti Blocco pregenerati; vedere 'Striped.CompactStriped'. Puoi avere un'applicazione con miliardi di ID univoci, ma il tuo lock pool rimane a 1024 sempre gli stessi lock. 'Striped' opera su una probabilità statisticamente MOLTO bassa di 2, o più, ID che generano lo stesso hash cercando di accedere al mutex allo stesso tempo. – Espinosa

0

Mantieni un mutex/blocco per secchio. Questo assicurerà che solo le collisioni attenderanno quel mutex.

0

Se il "record" di cui si parla è un oggetto mutabile e "aggiornamento" significa che lo stato interno dell'oggetto viene modificato senza disturbare la struttura del contenitore, quindi è possibile ottenere ciò che si desidera semplicemente bloccando l'oggetto record.

Se "aggiornamento" indica la rimozione dell'oggetto record dal contenitore e la sua sostituzione, è necessario bloccare l'intero contenitore per impedire che altri thread lo vedano in uno stato incoerente.

In entrambi i casi, è necessario osservare le classi nel pacchetto java.util.concurrent.

1

Questo è il modo; l'ho fatto. E sì, sono d'accordo se due stringhe diverse condividono lo stesso hashcode finendo con l'acquisizione dello stesso blocco.

class LockByKey { 
    ObjectForString objHolder = new ObjectForString(100); 
    public void lockThenWorkForKey (String key) { 
     synchronized(objHolder.valueOf(key)){ 
      //DoSomeWork 
     } 
    } 
} 

public final class ObjectForString { 

    private final Object[] cache; 
    private final int cacheSize; 
    final int mask; 

    public ObjectForString(int size) { 
     // Find power-of-two sizes best matching arguments 
     int ssize = 1; 
     while (ssize < size) { 
      ssize <<= 1; 
     } 

     mask = ssize - 1; 
     cache = new Object[ssize]; 
     cacheSize = ssize; 
     //build the Cache 
     for (int i = 0; i < cacheSize; i++) { 
      this.cache[i] = new Object(); 
     } 
    } 

    public Object valueOf(String key) { 
     int index = key.hashCode(); 
     return cache[index & mask]; 
    } 
} 
Problemi correlati