The several flavors of random in Java

March 14th, 2012 Jorge Lee, Consultant  (email the author)

Random number generation is one of most basic features in any programming language. The basic utilization is always the same: generate a random number between 0 and 1. With such a simple resource at hand we sometimes overlook some interesting features.

What do we learn from the books?

The most obvious and maybe intuitive way to generate random numbers in Java is simply calling:

java.lang.Math.random()

Random generation is in the Math utility class with abs, pow, floor, sqrt and other mathematical functions we see in all other languages. Most people will learn about this class in books, tutorials and classes. The utilization is simple: a double is returned between 0.0 and 1.0. With this basic information, a developer usually writes something like:

Math.random() * 10

…to generate a double between 0.0 and 10.0, and:

Math.round(Math.random() * 10)

…to generate a integer between 0 and 10. Static imports can make these expressions shorter but casting can be annoying, especially if wrapper classes are involved.

One step further

By reading the source code of Math.random() or simply playing with the IDE’s auto-completion feature, a developer can easily notice that java.lang.Math.random() uses an internal random generator object – a powerful object with the flexibility to generate randoms of booleans, all numeric types (with and without range) and even Gaussian distributed doubles. For example:

new java.util.Random().nextInt(10)

This amazing object does have one drawback, however: it is an object. Its methods are only accessible through an instance, which means the constructor must be called. Expressions like the one above are acceptable if memory is not an issue, but it feels that something is not right.

A simple solution to avoid creating a new instance of Random each time you need a random number is to have a singleton instance using a static class, but by doing this you will be essentially replicating what java.lang.Math does. Maybe a safe way is to copy the lazy initialization and have your improved version of java.lang.Math. This works, has low maintenance, but you may want some simple unit testing just to make sure it is working.

The storage problem comes from the assumption that the code which calls it only wants a random value. Sometimes there is a need to manipulate or protect the seed, an internal number used to store the state and calculate the next random number. In these special cases a public accessible random generator is not appropriate.

Concurrency

In a multi-threaded environment like a Java EE application, the random generator object instance can still be stored as a static attribute in a class or some other implementation of the singleton pattern. Fortunately, java.util.Random is thread-safe so there is no risk to corrupt the seed with calls from multiple threads.

Another option worth considering in a multi-threaded scenario is a java.lang.ThreadLocal instance. The idea of a lazy initialized singleton is implemented by a native Java API and you also have a guarantee of one instance object per thread. No more trouble with concurrency and no more trouble with unit testing.

One thing is still not right: Java did not provide a good way to manage the singleton java.util.Random instance and through this post it was discussed ways to build that. Well, the long awaited Java 7 provides a new way to generate random values:

java.util.concurrent.ThreadLocalRandom.current().nextInt(10)

This new API mixes the advantages of the two other approaches: singleton/static access like Math.random() and flexibility. ThreadLocalRandom is also faster than any other approach in high concurrence scenarios.

EDIT

Fellow summanoid Chris Marasti-Georg pointed that

Math.round(Math.random() * 10)

causes an unbalanced distribution, e.g.: 0.0 – 0.499999 will round to 0 while 0.5 to 1.499999 will round to 1. The correct way to achieve a balanced distribution with the old style syntax is

Math.floor(Math.random() * 11)

Fortunately we don’t have to worry if we are java.util.Random or java.util.concurrent.ThreadLocalRandom.
Effective Java item 47 describes some the dangers of not using the java.util.Random API in the correct way. The lesson is do not use

Math.abs(rnd.nextInt())%n

instead use the API as designed: rnd.nextInt(n).

Be Sociable, Share!

Entry Filed under: Agile and Development

5 Comments Add your own

  • 1. Eugeny  |  March 15th, 2012 at 10:11 am

    Math.round(Math.random() * 10)
    to generate a integer between 0 and 10
    It’s not correct. Because these will not uniform distribution.

    Math.round(Math.random() * 10-0.5) is correct

  • 2. sMoZely  |  March 15th, 2012 at 3:15 pm

    Hi, nice article …

    One thing I would add, in the concurrency section you say “Another option worth considering in a multi-threaded scenario” … but you never state why. Only in your last statement in that section do you hint at the speed benefit of using a ThreadLocal random.

    Just thinking from a reader who doesn’t know about java.util.Random perspective, I knew about Random long before I knew about ThreadLocal’s.

    Just a thought.

    Cheers,
    Steve

  • 3. Jorge Lee  |  March 15th, 2012 at 3:33 pm

    @Eugeny
    Your code works but you would have problems with zero not being balanced correctly. The right way would be using floor function. Casting has its tricks and problems. Chris spotted this problem yesterday but I could not update the post until today.

    @sMoZely
    While doing the research for this post I wrote a couple of experiments testing all the ways to generate random with single-threaded and multi-threaded scenarios. I verify that ThreadLocalRandom is faster than any other way in all scenarios. I didn’t want to spoil this post talking about concurrency so I saved everything for a next post. Stay tuned!

  • 4. ??Java??????? | MobileCN&hellip  |  August 5th, 2012 at 4:03 am

    [...] ?????summa-tech [...]

  • 5. Bing  |  March 20th, 2014 at 3:38 pm

    I_m not that much of a online reader to be honest but
    your sites really nice, keep it up! I’ll go ahead and bookmark your website to come back later.
    All the best

    Have a look at my blog post; Bing

Leave a Comment

Required

Required, hidden


3 + = five

Some HTML allowed:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Trackback this post  |  Subscribe to the comments via RSS Feed

© 2010-2014 Summa All Rights Reserved