Introduction to the

In JDK7, java.util.Concurrent includes a fairly handy class for generating random numbers, ThreadLocalRandom, when an application expects to use random numbers in multiple threads or ForkJoinTasks. For concurrent access, using TheadLocalRandom instead of Math.random() reduces contention and results in better performance. Use in just call ThreadLocalRandom. Current (), and then call it’s one way to get a random number. Here’s an example:

int randomNum = ThreadLocalRandom.current().nextInt(max);
Copy the code

Source code analysis

Linear congruence method

Linear congruent method is also called “linear congruent random number generator”. One of the methods of generating [0,1] uniformly distributed random numbers. Including mixed congruence method and multiplication congruence method. It was put forward by American Lemmer in 1951. Random in Java is used to generate Random numbers.

X[n + 1] = (a * X[n] + c) mod m

Among them,

  • M > 0, module data
  • 0 <= a <= m, multiplier
  • 0 <= c <= m, increment
  • 0 <= X0 < m, X0 start value

Random source code analysis

The following is the core source code for Random

private static final long multiplier = 0x5DEECE66DL;
private static final long addend = 0xBL;
private static final long mask = (1L << 48) - 1;

The constructor initializes this.seed
public Random(long seed) {
    if (getClass() == Random.class)
        this.seed = new AtomicLong(initialScramble(seed));
    else {
        // subclass might have overriden setSeed
        this.seed = newAtomicLong(); setSeed(seed); }}protected int next(int bits) {
    long oldseed, nextseed;
    AtomicLong seed = this.seed;
    do {
        oldseed = seed.get();
        nextseed = (oldseed * multiplier + addend) & mask;
    // CAS ensures thread safety, but there may be performance problems in multi-threading
    } while(! seed.compareAndSet(oldseed, nextseed));return (int)(nextseed >>> (48 - bits));
}


// Get a random number
public int nextInt(int bound) {
    if (bound <= 0)
        throw new IllegalArgumentException(BadBound);

    int r = next(31);
    int m = bound - 1;
    if ((bound & m) == 0)  // i.e., bound is a power of 2
        r = (int)((bound * (long)r) >> 31);
    else {
        for (int u = r;
             u - (r = u % bound) + m < 0;
             u = next(31)); }return r;
}
Copy the code

From the source code we can see that the core calculation is

nextseed = (oldseed * multiplier + addend) & mask;

Then substitute the fixed values to get the following formula

nextseed = (oldseed * 25214903917L + 11L) & 281474976710655L;

Seed can also be a random seed. Copy the formula again for easy reading

X[n + 1] = (a * X[n] + c) mod m

Where Multiplier and addend represent a and C in the formula respectively, but what does mask represent? X & [(1L << 48) — 1] is equivalent to x (mod 2^48). To explain: x mod 2 to the NTH power. Since the divisor is 2 to the NTH power, e.g. 0001,0010,0100,1000 is equivalent to moving the binary form of x to the right by N, and the remainder to the right of the decimal is the remainder, e.g. : 13 = 1101 8 = 1000 13/8 = 1.101, so 101 to the right of the decimal point is the remainder, which in decimal form is 5

Note: **AtomicLong seed**** indicates that Random is a thread-safe Random number utility class **

ThreadLocalRandom source code analysis

We can use ThreadLocalRandom. Current (), for instance.

public static ThreadLocalRandom current(a) {
        if (UNSAFE.getInt(Thread.currentThread(), PROBE) == 0)
            localInit();
        return instance;
}
Copy the code

LocalInit () is called if there is no initialization:

static final void localInit(a) {
    int p = probeGenerator.addAndGet(PROBE_INCREMENT);
    int probe = (p == 0)?1 : p; // skip 0
    long seed = mix64(seeder.getAndAdd(SEEDER_INCREMENT));
    Thread t = Thread.currentThread();
    UNSAFE.putLong(t, SEED, seed);
    UNSAFE.putInt(t, PROBE, probe);
}
Copy the code

We can see from the code that thread.currentthread () is used to get the currentThread. Note The process of generating random numbers does not depend on the CAS to obtain shared objects. Let’s finally look at the nextInt method:

public int nextInt(int bound) {
    if (bound <= 0)
        throw new IllegalArgumentException(BadBound);
    // Generate a random number
    int r = mix32(nextSeed());
    int m = bound - 1;
    // Random number judgment
    if ((bound & m) == 0) // power of two
        / / modulo
        r &= m;
    else { // reject over-represented candidates
        // Retry until interval requirements are met
        for (int u = r >>> 1;
             u + m - (r = u % bound) < 0;
             u = mix32(nextSeed()) >>> 1); }return r;
}
Copy the code

NextInt (int bound) is the same as nextInt(int bound). First call mix32(nextSeed()) to generate a random number (int range), then check the parameter n, if n is exactly a power of 2, So you just shift it and you get what you want; If it is not a power of 2, mod n is used to get the result in the range [0,n]. In addition, the purpose of the for loop statement is to prevent the result from being negative.

Here we can see mainly through mix32(nextSeed())

// Generate Random number according to the new seed. The algorithm for Random number is the same as Random
private static int mix32(long z) {
    z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL;
    return (int)(((z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L) > > >32);
}


/ / generated new seeds, preserved in the Thread. ThreadLocalRandomSeed. GAMMA=0x9e3779b97f4a7c15L
final long nextSeed(a) {
    Thread t; long r; // read and update per-thread seed
    UNSAFE.putLong(t = Thread.currentThread(), SEED,
                   r = UNSAFE.getLong(t, SEED) + GAMMA);
    return r;
}
Copy the code

Use case

Random

Here is how the Random class generates Random numbers

public class RandomTest {
    static Random RANDOM = new Random();

    public static void main(String[] args) {
        final int max = 1000000;
        for (int i = 0; i < 1000; i++) {
            new Thread(() -> {
                int randomNum = RANDOM.nextInt(max);
                System.out.println("randomNum: "+ randomNum); }).start(); }}}Copy the code

ThreadLocalRandom

Here is a simple ThreadLocalRandom as follows:

public class ThreadLocalRandomTest {

    public static void main(String[] args) {
        final int max = 1000000;
        for (int i = 0; i < 1000; i++) {
            new Thread(()-> {
                int randomNum = ThreadLocalRandom.current().nextInt(max);
                System.out.println("randomNum: "+ randomNum); }).start(); }}}// Output the result
randomNum: 648582
randomNum: 76984
randomNum: 561085
randomNum: 120131
randomNum: 210919
randomNum: 546645
randomNum: 194225
randomNum: 930034
randomNum: 203882
Copy the code

Used to summarize

** Prevents Random instances from being used by multiple threads, and while sharing the instance is thread-safe, performance degrades due to competing for the same seed. Random instances include instances of java.util.random or math.random (). Example: After JDK7, API ThreadLocalRandom can be used directly, whereas prior to JDK7, coding is required to ensure that each line holds a separate instance of Random.

The resources

  • The Art of Computer Programming, TACOP
  • Java Development Manual alibaba
  • www.cnblogs.com/shamo89/p/8…
  • Ifeve.com/tag/threadl…
  • www.cnblogs.com/softidea/p/…
  • Baike.baidu.com/item/%E7%BA…
  • www.cnblogs.com/binarylei/p…