Domanda

Ho usato LinkedHashMap con accessOrder true insieme a consentire un massimo di 500 voci in qualsiasi momento come cache LRU per i dati. Ma a causa di problemi di scalabilità, voglio passare a qualche alternativa thread-safe. ConcurrentHashMap sembra buono al riguardo, ma manca delle funzionalità di removeEldestEntry(Map.Entry e) e <=> presenti in <=>. Qualcuno può indicare un link o aiutarmi a facilitare l'implementazione.

È stato utile?

Soluzione

Di recente ho fatto qualcosa di simile con ConcurrentHashMap<String,CacheEntry>, in cui CacheEntry avvolge l'oggetto reale e aggiunge le statistiche di sfratto della cache: tempo di scadenza, tempo di inserimento (per sfratto FIFO / LIFO), ultimo tempo usato (per sfratto LRU / MRU), numero di hit (per sfratto LFU / MFU), ecc. Lo sfratto effettivo è sincronizzato e crea un ArrayList<CacheEntry> e fa un Collections.sort () su di esso usando il Comparatore appropriato per la strategia di sfratto. Poiché questo è costoso, ogni sfratto quindi elimina il 5% inferiore di CacheEntries. Sono sicuro che l'ottimizzazione delle prestazioni sarebbe comunque utile.

Nel tuo caso, dal momento che stai facendo FIFO, potresti tenere una ConcurrentLinkedQueue . Quando aggiungi un oggetto a ConcurrentHashMap, esegui un ConcurrentLinkedQueue.add () di quell'oggetto. Quando si desidera eliminare una voce, eseguire un ConcurrentLinkedQueue.poll () per rimuovere l'oggetto più vecchio, quindi rimuoverlo anche da ConcurrentHashMap.

Aggiornamento: altre possibilità in quest'area includono una raccolta Java sincronizzazione wrapper e Java 1.6 ConcurrentSkipListMap .

Altri suggerimenti

Hai provato a utilizzare una delle tante soluzioni di memorizzazione nella cache come ehcache? Puoi provare a utilizzare LinkedHashMap con un ReadWriteLock. Ciò ti darebbe l'accesso in lettura simultaneo.

Questo potrebbe sembrare vecchio ora, ma almeno solo per il mio tracciamento della cronologia, aggiungerò qui la mia soluzione: ho combinato ConcurrentHashMap che mappa K - > sottoclasse di WeakReference, ConcurrentLinkedQueue e un'interfaccia che definisce la deserializzazione degli oggetti valore basati su K per eseguire correttamente la memorizzazione nella cache LRU. La coda contiene riferimenti forti e il GC eliminerà i valori dalla memoria quando appropriato. Il monitoraggio delle dimensioni della coda ha comportato AtomicInteger, poiché non è possibile ispezionare la coda per determinare quando sfrattare. La cache gestirà lo sfratto / l'aggiunta alla coda e la gestione delle mappe. Se il GC ha eliminato il valore dalla memoria, l'implementazione dell'interfaccia di deserializzazione gestirà il recupero del valore. Ho anche avuto un'altra implementazione che prevedeva lo spooling su disco / rileggere ciò che era spool, ma era molto più lento della soluzione che ho pubblicato qui, dato che avevo sincronizzato lo spooling / lettura.

Lei dice di voler risolvere i problemi di scalabilità con un " thread-safe " alternativa. " Sicurezza della filettatura " qui significa che la struttura è tollerante di tentativi di accesso simultaneo, in quanto non subirà la corruzione per uso simultaneo senza sincronizzazione esterna. Tuttavia, tale tolleranza non aiuta necessariamente a migliorare & Quot; scalabilità & Quot ;. Nell'approccio più semplice, anche se di solito errato, proverai a sincronizzare la tua struttura internamente e a lasciare comunque non sicure le operazioni check-then-act non atomiche.

Le cache LRU richiedono almeno una certa consapevolezza della struttura totale. Hanno bisogno di qualcosa come un conteggio dei membri o la dimensione dei membri per decidere quando sfrattare, e quindi devono essere in grado di coordinare lo sfratto con tentativi simultanei di leggere, aggiungere o rimuovere elementi. Tentativo di ridurre la sincronizzazione necessaria per l'accesso simultaneo al & Quot; main & Quot; la struttura combatte contro il meccanismo di sfratto e impone che la politica di sfratto sia meno precisa nelle sue garanzie.

La risposta attualmente accettata menziona " quando vuoi sfrattare una voce " ;. Qui sta il problema. Come fai a sapere quando vuoi sfrattare una voce? Quali altre operazioni devi mettere in pausa per prendere questa decisione?

Avvolgi la mappa in Collections.synchronizedMap(). Se devi chiamare metodi aggiuntivi, quindi synchronize sulla mappa che hai ricevuto da questa chiamata e invoca il metodo originale sulla mappa originale ( vedi i javadocs per un esempio ). Lo stesso vale quando si esegue l'iterazione sui tasti, ecc.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top