Recientemente planteé una pregunta en stackoverflow, luego encontré la respuesta. La pregunta inicial era ¿Qué mecanismos distintos de los mutex o la recolección de basura pueden ralentizar mi programa Java de subprocesos múltiples?
Descubrí para mi horror que HashMap se ha modificado entre JDK1.6 y JDK1.7. Ahora tiene un bloque de código que hace que todos los hilos que crean HashMaps se sincronicen.
La línea de código en JDK1.7.0_10 es
/**A randomizing value associated with this instance that is applied to hash code of keys to make hash collisions harder to find. */
transient final int hashSeed = sun.misc.Hashing.randomHashSeed(this);
Que termina llamando
protected int next(int bits) {
long oldseed, nextseed;
AtomicLong seed = this.seed;
do {
oldseed = seed.get();
nextseed = (oldseed * multiplier + addend) & mask;
} while (!seed.compareAndSet(oldseed, nextseed));
return (int)(nextseed >>> (48 - bits));
}
Buscando en otros JDK, encuentro que esto no está presente en JDK1.5.0_22 o JDK1.6.0_26.
El impacto en mi código es enorme. Hace que cuando ejecuto en 64 subprocesos, obtengo menos rendimiento que cuando ejecuto en 1 subproceso. Una JStack muestra que la mayoría de los hilos pasan la mayor parte del tiempo girando en ese bucle en Random.
Entonces parece que tengo algunas opciones:
- Reescriba mi código para que no use HashMap, pero use algo similar
- De alguna manera juegue con el rt.jar y reemplace el hashmap dentro de él
- Meterse con la ruta de clases de alguna manera, por lo que cada hilo obtiene su propia versión de HashMap
Antes de comenzar por cualquiera de estos caminos (todos parecen llevar mucho tiempo y potencialmente de alto impacto), me preguntaba si me había perdido un truco obvio. ¿Alguno de ustedes puede sugerir personas de desbordamiento de pila cuál es el mejor camino, o quizás identificar una nueva idea?
Gracias por la ayuda