Нещодавно я підняв питання в stackoverflow, а потім знайшов відповідь. Початкове питання полягало в тому, які механізми, крім mutexx або збору сміття, можуть уповільнити мою багатопотокову програму 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
Перш ніж почати будь-який із цих шляхів (всі виглядають дуже трудомісткими та потенційно сильними), я подумав, чи не пропустив явного фокусу. Чи може хтось із вас перекласти людей, що переповнюють, припустити, що є кращим шляхом, або, можливо, визначити нову ідею.
Дякую за допомогу