Здравствуйте.
Помогите, пожалуйста, разобраться со следующей задачей:
Воспользуйтесь классом LongAccumulator для вычисления максимального и
минимального накапливаемых элементов.
Подразумевается, что должно быть несколько потоков, а вид генерации элементов произвольный.
Вот мой код:
import java.util.Random;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.LongAccumulator;
public class Main {
public static LongAccumulator maxValue = new LongAccumulator(Math::max, Integer.MIN_VALUE);
public static LongAccumulator minValue = new LongAccumulator(Math::min, Integer.MAX_VALUE);
public static void main(String[] args){
Random random = new Random();
// Executor executor = Executors.newCachedThreadPool();
Executor executor = Executors.newFixedThreadPool(1);
for (int i = 1; i <= 1000; i++) {
int taskId = i;
Runnable task = () -> {
for (int k = 1; k <= 100_000; k++){
int value = random.nextInt(1_000_000);
maxValue.accumulate(value);
minValue.accumulate(value);
}
System.out.println(taskId + ": min " + minValue.get() + ": max " + maxValue.get());
};
executor.execute(task);
}
}
}
Всё работает, но не так, как я ожидал. Если все задачи поместить в один поток (см. строку Executor executor = Executors.newFixedThreadPool(1);), то всё отрабатывает более-менее быстро.
Если же вместо этой строки подставить Executor executor = Executors.newCachedThreadPool();, или поставить несколько потоков: Executor executor = Executors.newFixedThreadPool(5);, то код работает в несколько раз дольше.
Собственно, вопрос состоит в том, почему это происходит и как сделать так, чтобы разделение задач на потоки не увеличивало время работы программы, а уменьшало.
UPD.
По совету, приведённому в комментариях, изменил код следующим образом, и программа стала работать быстрей в многопоточном режиме:
import java.util.Random;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.LongAccumulator;
public class Main {
public static LongAccumulator maxValue = new LongAccumulator(Math::max, Integer.MIN_VALUE);
public static LongAccumulator minValue = new LongAccumulator(Math::min, Integer.MAX_VALUE);
public static void main(String[] args){
Executor executor = Executors.newCachedThreadPool();
Runnable task; // вынес объявление из цикла ниже
for (int i = 1; i <= 1000; i++) {
Random random = new Random(); // для каждой задачи создаётся свой Random
int taskId = i;
task = () -> {
for (int k = 1; k <= 100_000; k++){
int value = random.nextInt(1_000_000);
maxValue.accumulate(value);
minValue.accumulate(value);
}
System.out.println(taskId + ": min " + minValue.get() + ": max " + maxValue.get());
};
executor.execute(task);
}
}
}
Ответ
Вынесите объявление Runnable класса из цикла. 1000 потоков (для cachedPool будет именнно так) не даст эффективности - jvm будет между ними переключаться постоянно, а т.к. тело задачи довольно "быстрое" то и эффекта это особо не даст. Поставьте кол-во потоков равным количеству ядер вашего CPU. Random для каждой задачи используйте свой
Комментариев нет:
Отправить комментарий