2010-02-13 16 views
41

¿Se puede reescribir la siguiente pieza de código sin usar Collections.synchronizedMap() manteniendo la corrección en concurrencia?¿Existe el equivalente de java.util.concurrent para WeakHashMap?

Collections.synchronizedMap(new WeakHashMap<Class, Object>()); 

i.e. ¿hay algo de java.util.concurrent que se pueda usar en su lugar? Tenga en cuenta que la simple sustitución con

new ConcurrentHashMap<Class, Object>(new WeakHashMap<Class, Object>())); 

, obviamente, no va a funcionar

+1

El beneficio importante de las estructuras de datos altamente concurrentes tales como 'ConcurrentHashMap' es que puede (a través de una variedad de técnicas) permanecerá thread-safe bajo carga pesada sin (mucho) bloqueando Es importante darse cuenta de que si su clase no tiene mucha carga, su rendimiento con ConcurrentHashMap podría ser * peor * que con HashMap. Si se espera que su entorno esté libre de controversias, puede usar la sincronización externa y estará bien. – scottb

Respuesta

33

GuavaCacheBuilder clase le permite hacer esto fácilmente.

CacheBuilder.newBuilder().weakKeys().build() 

Tenga en cuenta que esto cambia la semántica clave de Igualdad que se == en lugar de .equals() que no importa en su caso de utilizar Class casos, pero es un problema potencial.

+0

¿hay forma de personalizar la semántica de la igualdad a igual habitual? – gstackoverflow

+0

Enlace actualizado a Guava: https://github.com/google/guava y enlace actualizado para CacheBuilder: https://google.github.io/guava/releases/18.0/api/docs/com/google/common/ cache/CacheBuilder.html –

18

no creo que hay. De hecho, javadoc sugiere usar Collections.synchronizedMap()

"Al igual que la mayoría de las clases de colección, esta clase no está sincronizada. Se puede construir un WeakHashMap sincronizado utilizando el método Collections.synchronizedMap".

+0

desafortunado que no tiene un método putIfAbsent ... – rogerdpack

+0

@rogerdpack: pero siempre se puede componer un WeakHashMap en un 'Roll ThreadSafeWeakHashMap' y, con un bloqueo de monitor, escribir su propio putIfAbsent (...) con bastante facilidad. Estoy de acuerdo en que esto no sería óptimo bajo cargas pesadas, pero no todo está muy cargado. – scottb

+1

@rogerdpack lo hace ahora, Java 8 ftw – qualidafial

-1

¿Sigue funcionando correctamente el WeakHashMap en un mapa sincronizado para lo que desea hacer, ya que el recolector de elementos no utilizados puede modificar las referencias débiles directamente en cualquier momento, evitando el contenedor de mapas sincronizados? Creo que WeakHashMap solo funciona realmente en un único modelo de subprocesos.

0

¿El envolviendo el WeakHashMap en un mapa sincronizada todavía funcionan correctamente para lo que quiere hacer, ya que el recolector de basura puede modificar las WeakReferences directamente en cualquier momento, sin pasar por el sincronizada envoltorio mapa? Creo que WeakHashMap solo funciona realmente en un modelo de rosca simple .

Como se mencionó anteriormente, la documentación para WeakHashMap en https://docs.oracle.com/javase/7/docs/api/java/util/WeakHashMap.html específicamente dice:

"Un WeakHashMap sincronizado se pueden construir utilizando el método Collections.synchronizedMap"

Lo que implica para mí que esta técnica debe funcionar en conjunto con el comportamiento del recolector de basura (a menos que la documentación tenga errores)

+0

Correcto. La JVM siempre tiene múltiples subprocesos. Hay subprocesos de GC, subprocesos de finalizador y otros. Si WeakHashMap no funcionó en un programa Java explícitamente multiproceso, es difícil ver cómo podría funcionar en uno solo. – Doradus

0

Cafeine es un competidor popular de la memoria caché de Guava.

- keys automatically wrapped in weak references 
- values automatically wrapped in weak or soft references 

uso:

LoadingCache<Key, Graph> graphs = Caffeine.newBuilder() 
.weakKeys() 
.weakValues() 
.build(key -> createExpensiveGraph(key)); 
Cuestiones relacionadas