Subclassing java.util.Random
In our discussion of the XORShift generator, we mentioned that
we could subclass java.lang.Random to use a different generator.
There is essentially one method that we
need to override: the protected method
next(), which other methods will call to
ask for a certain number of random bits. Here is a naive version, which we'll
actually need to correct slightly in a moment:
public class XORShiftRandom extends Random {
private long seed = System.nanoTime();
public XORShiftRandom() {
}
protected int next(int nbits) {
// N.B. Not thread-safe!
long x = this.seed;
x ^= (x << 21);
x ^= (x >>> 35);
x ^= (x << 4);
this.seed = x;
x &= ((1L << nbits) -1);
return (int) x;
}
}
In principle, we don't actually care about nbits: the
XORShift algorithm produces numbers where we can take all bits as equally random.
However, it turns out that other methods of Random rely on exactly
the right number of random bits being supplied, and other bits being zero.
(In my opinion, the documentation of the next() method is misleading on this point.)
So, the line x &= ((1L << nbits) -1) masks off any unwanted bits.
A few details we've glossed over:
- The implementation above is not thread-safe, whereas
the base java.lang.Random is. If we wanted to fix this, we'd declare
seed as an AtomicLong and use an atomic update:
see the source code to java.lang.Random for an example, plus this site's tutorial on the Java atomic classes.
- Our implementation wouldn't serialise its state (current seed),
unlike java.lang.Random.
- We might want to override nextLong(), since we can generate 64 bits
at a time. This method would then not be able to generate the value zero, of course,
but as it stands, there'll always be one value that nextLong() can't
generate, since the generator has a period of 264-1, and there are
264 possible longs.
If you enjoy this Java programming article, please share with friends and colleagues. Follow the author on Twitter for the latest news and rants.
Editorial page content written by Neil Coffey. Copyright © Javamex UK 2021. All rights reserved.