Как уже упоминал Алекс, эту проблему можно легко распределить по нескольким потокам.
Давайте рассмотрим однопоточную реализацию с использованием потоков Java8:
Stream<BigInteger> numbers = LongStream.rangeClosed(1, 1_000_000).mapToObj(BigInteger::valueOf);
BigInteger reduced = numbers.reduce(BigInteger.ONE, BigInteger::multiply);
Теперь давайте рассмотрим нескольковерсия того же с резьбой:
Stream<BigInteger> numbers = LongStream.rangeClosed(1, 1_000_000).mapToObj(BigInteger::valueOf);
numbers = numbers.parallel();
BigInteger reduced = numbers.reduce(BigInteger.ONE, BigInteger::multiply);
(Да, единственное отличие - numbers = numbers.parallel();
- красота потоков)
Второй - намного быстрее, чемпервый (в зависимости от количества реальных и гиперпоточных процессоров, которые у вас есть), но получает тот же результат.
По какой-то причине, которую я пока не могу полностью объяснить, параллельная версия - намного быстрее, чем непараллельная версия.Вероятно, это связано с использованием памяти.На моем 4-ядерном 2,5 ГГц i7 MacBook Pro для параллельной версии требуется 5,8 секунды, но непараллельная версия не завершается даже за 10 минут (на 1 миллион).
Для 100 000параллельная версия намного быстрее: 90 миллисекунд для параллельной версии 2500 миллисекунд для непараллельной (измеряется 10-я итерация после 9 итераций прогрева).