¿Cuál es el razonamiento detrás de la doble llamada a WeakHashMap.put (..)?
-
05-07-2019 - |
Pregunta
Esta publicación de blog muestra una forma de implementar un mutex por idioma de id de cadena. Los identificadores de cadena utilizados son para representar identificadores HttpSession.
- ¿Por qué necesitamos ajustar una WeakReference alrededor de las instancias de Mutex? ¿No es mejor crear un Mapa desde String? & Gt; Mutex?
-
¿Por qué necesitamos llamar a put dos veces?
public Mutex getMutex( String id ) { Mutex key = new MutexImpl( id ); synchronized( mutexMap ) { WeakReference<Mutex> ref = mutexMap.get( key ); if( ref == null ) { mutexMap.put( key, new WeakReference<Mutex>( key ) ); return key; } Mutex mutex = ref.get(); if( mutex == null ) { mutexMap.put( key, new WeakReference<Mutex>( key ) ); return key; } return mutex; } }
Solución
Loop y Bruno Conde lo he cubierto bastante, pero desde que escribí ese código ...
El objetivo del diseño era evitar que el usuario llamara a un mecanismo de liberación: el mutex es elegible para la recolección de basura cuando el usuario ya no hace referencia a él.
¿Por qué necesitamos envolver una referencia débil? alrededor de las instancias de Mutex?
El mapa es un WeakHashMap :
private final Map mutexMap = new WeakHashMap();
Este mapa se usa para mantener una referencia al mutex, pero si usa el mismo objeto para la clave y el valor, el objeto no es elegible para la recolección de basura. Javadoc:
Nota de implementación: los objetos de valor en un WeakHashMap son propiedad de ordinarios referencias fuertes Por lo tanto, se debe tener cuidado tomado para asegurar que los objetos de valor no se refieren fuertemente a sus propias claves, ya sea directa o indirectamente, ya que eso evitará que las llaves sean descartado. Tenga en cuenta que un objeto de valor puede referirse indirectamente a su clave a través de el propio WeakHashMap; eso es un objeto de valor puede referirse fuertemente algún otro objeto clave cuyo asociado objeto de valor, a su vez, se refiere fuertemente a la clave del primer objeto de valor. Una forma de lidiar con esto es envolver se valoran dentro de WeakReferences antes de insertar, como en: m.put (clave, nuevo WeakReference (valor)), y luego desenvolviendo en cada get.
¿No es así? mejor simplemente crear un Mapa desde Cadena - > Mutex?
¿Cuándo se recolectará ese valor de cadena? ¿Se pasa siempre la misma referencia? Tiene interno () ha sido llamado? Si llamo interno, ¿cuánto tiempo durará la cadena? Si una cadena era la clave, el mutex podría no ser elegible para la recolección de basura mucho después de que no haya necesidad de mantener una referencia a él.
¿Por qué necesitamos llamar a put dos veces?
Hay dos casos para manejar hasta que el método pueda obtener una referencia fuerte al mutex en el mapa:
- el WeakReference tiene sido recolectado basura (o nunca estuvo allí en primer lugar)
- el contenido de WeakReference es basura recolectada después de que se ha adquirido la referencia a ella
put solo se invocará una vez; el método vuelve inmediatamente después.
(La WeakReference podría reutilizarse en el segundo puesto, pero no veo que sea una mejora significativa).
Por supuesto, si alguien puede encontrar fallas en el código, avíseme y con gusto lo corregiré. Además, las pruebas unitarias intentan verificar que la implementación no tenga fugas, así que siéntase libre de modificar el código y ver qué sucede cuando ejecuta las pruebas.
Otros consejos
Los objetos de valor en un WeakHashMap se encuentran en referencias fuertes comunes. Por lo tanto, se debe tener cuidado para garantizar que los objetos de valor no se refieran fuertemente a sus propias claves, ya sea directa o indirectamente, ya que eso evitará que las claves se descarten. Tenga en cuenta que un objeto de valor puede referirse indirectamente a su clave a través del propio WeakHashMap; es decir, un objeto de valor puede referirse fuertemente a algún otro objeto clave cuyo objeto de valor asociado, a su vez, se refiere fuertemente a la clave del primer objeto de valor. Una forma de lidiar con esto es envolver los valores dentro de WeakReferences antes de insertarlos, como en: m.put (key, new WeakReference (value)), y luego desenvolverlos en cada get.
1 - @Loop tiene un buena respuesta .
2 - Suponiendo que las entradas están envueltas con WeakReferences, la segunda put
es necesaria porque esa WeakReference
puede recopilarse antes de que la ejecución llegue a la línea:
Mutex mutex = ref.get();
En este caso:
- la entrada puede no existir en el
map
- si existe, se puede recopilar antes de la ejecución de
Mutex mutex = ref.get ();
Diría que las WeakReference
se usan solo porque necesitan referirse a los identificadores de sesión http. No siempre puede estar 100% seguro de recibir una notificación de que una sesión finaliza, lo que provocaría un mapa cada vez mayor.
La primera vez que llamas ponerlo es porque el mapa no contiene tu clave. La segunda vez es porque el mapa contenía la clave pero la referencia ya no existía.