Niedawno zadałem pytanie w stackoverflow, a potem znalazłem odpowiedź. Początkowe pytanie brzmiało: Jakie mechanizmy inne niż muteksy lub czyszczenie pamięci mogą spowolnić mój wielowątkowy program Java?
Ku mojemu przerażeniu odkryłem, że HashMap został zmodyfikowany między JDK1.6 a JDK1.7. Ma teraz blok kodu, który powoduje synchronizację wszystkich wątków tworzących HashMaps.
Wiersz kodu w JDK1.7.0_10 to
/**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);
Co kończy się dzwonieniem
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));
}
Patrząc na inne zestawy JDK, stwierdzam, że nie ma tego w JDK1.5.0_22 lub JDK1.6.0_26.
Wpływ na mój kod jest ogromny. To sprawia, że gdy uruchamiam się na 64 wątkach, uzyskuję mniejszą wydajność niż podczas uruchamiania na 1 wątku. JStack pokazuje, że większość wątków spędza większość czasu w tej pętli w trybie Random.
Więc wydaje mi się, że mam kilka opcji:
- Przepisz mój kod, abym nie używał HashMap, ale użyj czegoś podobnego
- Jakoś pomieszaj z rt.jar i wymień hashmap w nim
- Zepsuć w jakiś sposób ścieżkę klasy, więc każdy wątek otrzymuje własną wersję HashMap
Zanim rozpocznę którąkolwiek z tych ścieżek (wszystkie wyglądają na bardzo czasochłonne i potencjalnie duże), zastanawiałem się, czy nie przegapiłem oczywistej sztuczki. Czy ktoś z was może zasugerować, która z przepełnionych stosów jest lepszą ścieżką, lub może zidentyfikować nowy pomysł.
Dzięki za pomoc