-2

I wrote this Java method which takes about one second to run (on my computer):

    /**
     * This method takes about one second to run.
     */
    private long eseguiUnitàDiLavoro() {
        double x, y = 1000;
        final long start_time, stop_time;

        start_time = System.currentTimeMillis();
        for (int i = 0; i < 20000000; i++) {
            x = Math.random();
            y = y / Math.atan(x);
        }
        stop_time = System.currentTimeMillis();
        return stop_time - start_time;
    }

If I run that method five times (L0, L1, L2, L3, L4) I get these times:

  • L0 takes 1099 ms,
  • L1 takes 1114 ms,
  • L2 takes 1099 ms,
  • L3 takes 1098 ms,
  • L4 takes 1100 ms.

And the overall execution time is 5510 ms (about five times the time that each task takes). And this is fine.

But if I build that method as a thread, and I run it five times, I get these times:

  • L0 takes 15729 ms,
  • L1 takes 15635 ms,
  • L2 takes 15557 ms,
  • L3 takes 15714 ms,
  • L4 takes 15604 ms.

The overall execution time is now 15745 ms.

The tasks execution order is now L1 L2 L4 L3 L0, and this is fine.

But I expected the overall execution time was the same in both cases. Conversely when the multithreading approach was used, it was about three times slower than the mono threading one.

I expected the multithreading approach was slightly slower than mono threading (due to some scheduler overhead) but three times slower is too much for me. What did I misunderstand?

I also expected that the tasks L0, L1, L2, ... each took about 5 seconds and they, started together, stopped together too. In fact, they started together and stopped together, but each took about fifteen seconds.

Can someone explain to me why multithreading processing is so inefficient? Thank you all

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
geko
  • 11
  • 4
  • Does this answer your question? [How do I write a correct micro-benchmark in Java?](https://stackoverflow.com/questions/504103/how-do-i-write-a-correct-micro-benchmark-in-java) – Johannes Kuhn Dec 23 '22 at 20:06
  • I rolled back your question to the **version that was answered**. Please do not change questions to something completely different after they have been answered. If you have a new question, then post it as a new question. – Adrian Mole Dec 30 '22 at 00:56
  • Ok Andrian, I posted a new one. – geko Jan 02 '23 at 18:11

1 Answers1

3

There are lots of possible explanations, including that you coded the multithreading solution wrong, but the one that jumps out at me is that Math.random() is fully synchronized and can't be run concurrently. Its documentation actually calls this out:

However, if many threads need to generate pseudorandom numbers at a great rate, it may reduce contention for each thread to have its own pseudorandom-number generator.

Using ThreadLocalRandom or separate Random objects instead of Math.random() would address that concern.

In general, though, this is likely to be about your code, not about multithreading in general. (Other possibilities that occur to me include how you're measuring the time consumption and how many cores are actually available on your machine.)

Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
  • 1
    Yes Louis, thanks a lot. I substituted Math.random() with the java.util.Random class and the nextDouble() method and now times are different. Now I get the following overall execution time (in multithreading): 1160 ms. But it doesn't look realistic. In my original post it was about 15 seconds (too high), now it is about 1 second (too low), as multithreading doesn't create processing power. Maybe there is still something wrong... – geko Dec 23 '22 at 19:17
  • That sounds related to JIT behavior and how simply measuring the passage of time on your code can produce misleading benchmark results. – Louis Wasserman Dec 23 '22 at 19:20
  • @geko how many threads do you use? You write that _multithreading doesn't create processing power_, but modern CPUs can execute 8 or more threads **in parallel** (depending on how cores it has - my machine for example has 8 cores and can execute 16 threads parallel). With 5 threads on a machine that can run 5 or more threads parallel each task (L0 to L4) still only needs about 1100 milliseconds and they can run truly parallel so if you start them together they will all finish after about 1100 milliseconds. – Thomas Kläger Dec 23 '22 at 21:11