Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace instances of Math.random with Random.nextDouble #673

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

bd2019us
Copy link

There is a performance overhead associated with Math.random these is unassociated with Random.nextDouble, which performs the same functionality as Math.random. Switching to Random.nextdouble removes this redundancy overhead.

@pzygielo
Copy link

I have the same question as for apache/camel#2908 (comment)

@audun
Copy link

audun commented May 12, 2019

Creating a new instance of Random and calling nextDouble on it once? What about the overhead of new Random();?

Math.random is initialized once and reuses it, though shares it between threads so it needs to be synchronized.

This method is properly synchronized to allow correct use by more than one thread. 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.

@audun
Copy link

audun commented May 15, 2019

I ran some benchmarks.

    @Benchmark
    public void mathRandom(Blackhole bh) {
        for (int i = 0; i < N; i++) {
            double d = Math.random();
            bh.consume(d);
        }
    }

    @Benchmark
    public void newRandom(Blackhole bh) {
        for (int i = 0; i < N; i++) {
            Random rand = new Random();
            double d = rand.nextDouble();
            bh.consume(d);
        }
    }

    @Benchmark
    public void reuseNewRandom(Blackhole bh) {
        Random rand = new Random();
        for (int i = 0; i < N; i++) {
            double d = rand.nextDouble();
            bh.consume(d);
        }
    }

In a single-threaded benchmark the proposed way is about three times slower than Math.random:

Benchmark                          (N)  Mode  Cnt    Score    Error  Units
BenchmarkLoop.mathRandom      10000000  avgt   10  228.864 ±  2.904  ms/op
BenchmarkLoop.newRandom       10000000  avgt   10  749.884 ±  8.158  ms/op
BenchmarkLoop.reuseNewRandom  10000000  avgt   10  236.233 ± 11.580  ms/op

Since Math.random is synchronized it has significant problems in a multi-threaded benchmark:

Benchmark                          (N)  Mode  Cnt      Score     Error  Units
BenchmarkLoop.mathRandom      10000000  avgt   10  12878.414 ± 628.863  ms/op
BenchmarkLoop.newRandom       10000000  avgt   10   5583.754 ± 221.973  ms/op
BenchmarkLoop.reuseNewRandom  10000000  avgt   10    270.047 ±  14.086  ms/op

Note that this benchmark is quite unrealistic for most workloads, since it's doing nothing apart from generating random numbers and will hit the synchronization lock every single time.

The consistent winner here seems to be a thread-local Random object and repeatedly getting a random number from that.

@martin-g
Copy link
Member

java.util.concurrent.ThreadLocalRandom FTW!

@janhoy janhoy added the missing Jira PR is missing a Jira issue label Mar 6, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
missing Jira PR is missing a Jira issue
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants