Hello. Please help me with the following task:

Use the LongAccumulator class to calculate the maximum and minimum accumulated items.

It is understood that there should be several streams, and the type of generation of elements is arbitrary. Here is my code:

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); } } } 

Everything works, but not as I expected. If all tasks are put into one thread (see the Executor executor = Executors.newFixedThreadPool(1); ) line, then everything works out more or less quickly. If instead of this line we substitute Executor executor = Executors.newCachedThreadPool(); , or put several threads: Executor executor = Executors.newFixedThreadPool(5); , the code works several times longer. Actually, the question is why this is happening and how to make it so that the division of tasks into threads does not increase the running time of the program, but reduces it.

UPD. According to the advice given in the comments, I changed the code as follows, and the program began to work faster in multi-threaded mode:

 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); } } } 

    1 answer 1

    1. Remove the runnable class from the loop.
    2. 1000 threads (for cachedPool will be exactly like that) will not give efficiency - jvm will switch between them constantly, but since the body of the task is rather "fast", and this will not give much effect. Set the number of threads equal to the number of cores in your CPU.
    3. Random for each task, use your own
    • Thank. Indeed, the "bottleneck" was General Random. Moved according to your advice inside the cycle, and the brakes are gone. Delivered also Runnable before the cycle, but did not receive a tangible increase. it seemed that he had earned a little quicker, but I certainly don’t argue. - golubtsoff
    • Removing Runnable from the cycle will save the memory and nerves of the Garbage Collector :-) - Alexander Martyntsev