Недавно я задал вопрос в stackoverflow, а затем нашел ответ. Первоначальный вопрос был Какие механизмы, кроме мьютексов или сбор мусора, могут замедлить мою многопоточную java-программу?
Я с ужасом обнаружил, что HashMap был изменен между JDK1.6 и JDK1.7. Теперь он имеет блок кода, который заставляет все потоки создавать HashMaps для синхронизации.
Строка кода в JDK1.7.0_10
/**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);
Который заканчивается вызовом
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));
}
В других JDK я обнаружил, что это нет в JDK1.5.0_22 или JDK1.6.0_26.
Влияние на мой код огромно. Это делает так, что, когда я запускаю 64 потока, я получаю меньше производительности, чем когда я запускаю 1 поток. JStack показывает, что большинство потоков тратят большую часть своего времени на вращение в этом цикле в Random.
Итак, у меня есть несколько вариантов:
- Перепишите мой код, чтобы я не использовал HashMap, но использую что-то подобное
- Как-то возиться с rt.jar и заменить хэш-карту внутри него
- Беспорядок с пути класса каким-то образом, поэтому каждый поток получает свою собственную версию HashMap
Прежде чем начать любой из этих путей (все выглядят очень много времени и потенциально сильно влияют), я задавался вопросом, не пропустил я очевидный трюк. Может ли кто-нибудь из вас переполнять поток людей, которые указывают на лучший путь или, возможно, идентифицируют новую идею.
Спасибо за помощь