Основная проблема в вашем коде заключается в том, что Calculation
фактически является оберткой для общей переменной (поле count
), которая обновляется без какой-либо синхронизации.
Существует три способа решенияэто:
- синхронизировать переменную;например, используя
synchronized
в соответствующих точках - используйте атомарный тип для переменной
- , не используйте общую переменную.
Третий вариант:лучше с точки зрения производительности, а реализация проста;см. ответ @ JenniferP.
Обратите внимание, что дополнительная синхронизация не требуется, если вы предоставляете каждому потоку свой собственный Calculation
объект. происходит до того, как отношения , связанные с вызовами Thread::start()
и Thread::join()
, гарантируют, что основной поток увидит правильные результаты из дочерних потоков при чтении их после объединения.
Для чего стоит поточная безопасная реализация Calculation
, которая будет работать при совместном использовании экземпляра, будет выглядеть так:
class Calculation {
private long total = 0;
public void calcSum(long start, long end) {
for (long i = start; i <= end; i++) {
increment(i);
}
}
public synchronized long getTotal() {
return total;
}
private synchronized void increment(long by) {
total += by;
}
}
Обратите внимание, что вам нужно синхронизировать оба на геттереи метод приращения.Альтернативой является использование AtomicLong
для представления итога.Но в обоих случаях будут значительные издержки из-за использования разделяемой переменной.(В версии с synchronized
издержки могут быть чрезмерными из-за конфликта блокировок. Я был бы удивлен, если бы было какое-либо ускорение по сравнению с однопоточной версией. Даже если бы вы могли устранить накладные расходы на создание потоков.)