Попробуйте отключить -XX:-UseBiasedLocking
Возможно, он пинг-понг, пока код не будет оптимизирован (попробуйте -XX:+PrintCompilation
, а затем он эффективно определяет, что программа будет работать быстрее, если только один поток удерживает блокировку. Например, синхронизированный эффективно выходит за пределыloop.
Такое поведение будет часто наблюдаться, когда вы используете несколько потоков для выполнения чего-то более быстрого, чем однопоточное.
Вы можете либо каждый поток альтернативно увеличивать значение, либоВы можете запустить один цикл до остановки (в Integer.MAX_VALUE), а затем второй.
public class CountingWithThreads {
static long count1 = 0;
static long count2 = 0;
public static void main(String... args) throws InterruptedException {
long start1 = System.nanoTime();
Thread t1a = new Thread(new CountsSingleThreaded(Integer.MAX_VALUE));
Thread t1b = new Thread(new CountsSingleThreaded(Integer.MAX_VALUE));
t1a.start();
t1b.start();
t1a.join();
t1b.join();
long time1 = System.nanoTime() - start1;
System.out.printf("Single threaded, took %.1f second to count to %,d%n", time1 / 1e9, count1);
long start2 = System.nanoTime();
Thread t2a = new Thread(new CountsAlternatively(true, 1000000));
Thread t2b = new Thread(new CountsAlternatively(false, 1000000));
t2a.start();
t2b.start();
t2a.join();
t2b.join();
long time2 = System.nanoTime() - start2;
System.out.printf("Alternating multi-threaded took %.1f second to count to %,d%n", time2 / 1e9, count2);
}
static class CountsSingleThreaded implements Runnable {
private final long maxValue;
CountsSingleThreaded(long maxValue) {
this.maxValue = maxValue;
}
public void run() {
synchronized (CountingWithThreads.class) {
for (long i = 0; i < maxValue; i++) {
count1++;
}
}
}
}
static class CountsAlternatively implements Runnable {
private final boolean even;
private final long maximum;
CountsAlternatively(boolean even, long maximum) {
this.even = even;
this.maximum = maximum;
}
public void run() {
try {
synchronized (CountingWithThreads.class) {
while (count2 < maximum)
if (((count2 & 1) == 0) == even) {
count2++;
CountingWithThreads.class.notify();
} else {
CountingWithThreads.class.wait();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
печатает
Single threaded, took 2.3 second to count to 4,294,967,294
Alternating multi-threaded took 3.4 second to count to 1,000,000
Запуск одного потока до завершения по одномунаиболее эффективный. Если принудительно чередовать счетчики (самый экстремальный пример многопоточности), это будет более чем в 1000 раз медленнее.