Почему с использованием многопоточности быстродействие программы не растет?
Решил сравнить скорости вычисления с использованием многопоточности и без использования. Для этого один и тот же цикл запустил обычным способом без применения многопоточности, во втором случае (закомментировано) запустил пять потоков. Если я всё правильно понимаю, то программа во втором случае должна выполняться в 5 раз быстрее. Но почему-то когда запускаю 5 потоков, программа выполняется очень долго, а может и бесконечно, выполнения я не дождался. Вопрос: почему так, может в коде что-то не учел?
public class Test {
public static void main(String[] args) throws InterruptedException {
MyFirstThread mft = new MyFirstThread();
mft.run();
// Thread t1 = new Thread(mft);
// Thread t2 = new Thread(mft);
// Thread t3 = new Thread(mft);
// Thread t4 = new Thread(mft);
// Thread t5 = new Thread(mft);
// t1.start();
// t2.start();
// t3.start();
// t4.start();
// t5.start();
}
public static class MyFirstThread implements Runnable {
public volatile int t = 0;
public void run() {
Date date1 = new Date();
while (t<1000000000){
t+=1;
}
Date date2 = new Date();
System.out.println(date2.getTime()-date1.getTime());
}
}
}
И в заключении еще вопрос: правильно ли я понимаю, что если, например, у меня 1-ядерный процессор, то из преимуществ использования многопоточности быстродействие я не получаю?
Ответы (1 шт):
Операция увеличения t:
t+=1;
Не атомарная. Она фактически состоит из двух операций: считывания значения и присвоения нового значения. Пока один поток считал значение и увеличивает его на единицу, другой поток также считывает это же значение и пытается присвоить его заново. Более того «отстающий» поток может затереть результаты «опережающего»:
Поток 1: получил значение t=1
Поток 2: получил значение t=1
Поток 2: записал значение t=2
Поток 2: получил значение t=2
Поток 2: записал значение t=3
Поток 1: записал значение t=2
Таким образом потоки не помогают друг другу, по очереди увеличивая t, а скорее мешают. Добавьте к этому расходы на доступ к общей памяти и получите объяснение сильного падения производительности.
volatile здесь недостаточно. Можно синхронизировать доступ к t (сделать увеличение атомарным), но это приведет к блокировкам между потоками и сведет на нет преимущества многопоточности. Улучшить производительность можно за счет изменения логики разделения труда между потоками. Например, если каждый поток будет считать собственный счетчик, а выходить по условию общей суммы.