Ich habe kürzlich eine Frage in stackoverflow gestellt und dann die Antwort gefunden. Die erste Frage war: Welche anderen Mechanismen als Mutexe oder Garbage Collection können mein Java-Programm mit mehreren Threads verlangsamen?
Zu meinem Entsetzen stellte ich fest, dass HashMap zwischen JDK1.6 und JDK1.7 geändert wurde. Es hat jetzt einen Codeblock, der bewirkt, dass alle Threads, die HashMaps erstellen, synchronisiert werden.
Die Codezeile in JDK1.7.0_10 lautet
/**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);
Was am Ende anruft
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));
}
Wenn ich in anderen JDKs nachschaue, finde ich, dass dies in JDK1.5.0_22 oder JDK1.6.0_26 nicht vorhanden ist.
Die Auswirkungen auf meinen Code sind enorm. Es macht es so, dass wenn ich auf 64 Threads laufe, ich weniger Leistung bekomme als wenn ich auf 1 Thread laufe. Ein JStack zeigt, dass die meisten Threads die meiste Zeit damit verbringen, sich in dieser Schleife in Random zu drehen.
Ich habe also einige Möglichkeiten:
- Schreiben Sie meinen Code neu, damit ich keine HashMap verwende, sondern etwas Ähnliches
- Spielen Sie irgendwie mit dem rt.jar herum und ersetzen Sie die darin enthaltene Hashmap
- Verwirren Sie sich irgendwie mit dem Klassenpfad, sodass jeder Thread seine eigene Version von HashMap erhält
Bevor ich einen dieser Pfade beschreite (alle sehen sehr zeitaufwändig und potenziell wirkungsvoll aus), habe ich mich gefragt, ob ich einen offensichtlichen Trick verpasst habe. Kann jemand von euch Überlauf-Leute vorschlagen, welcher der bessere Weg ist, oder vielleicht eine neue Idee identifizieren?
Danke für die Hilfe