Java Programming Tutorials

Java programming tutorials with many code examples!

Generate random numbers concurrently – ThreadLocalRandom

Until Java 7 there was no simple and effective way to generate random numbers concurrently. Here we show ThreadLocalRandom to generate random numbers in a thread-safe way.

One of the most notable additions in Java 7 was Fork Join Framework. But not many people know that it came with a bunch of classes useful in parallel computations. One of them is java.util.concurrent.ThreadLocalRandom. The class used in concurrent programs causes less overhead and contention than shared Random (which is not thread-safe as you probably know).

Thread safe random number generator

The usage of ThreadLocalRandom is pretty simple. We need to call current() static method to obtain a ThreadLocal version and then just obtain random numbers as usual. Here we use ints() from Java 8 to get stream of random ints and collect them into a List:

package com.farenda.java.util.concurrent;

import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

import static java.util.stream.Collectors.toList;

public class ConcurrentRandomNumbers {

    public List<Integer> randomRange(int from, int howMany) {
        return ThreadLocalRandom.current()
                .ints(howMany, from, from+howMany)
                .boxed()
                .collect(toList());
    }
}

In the below program we’re going to use this method from concurrently executed tasks.

Generating random numbers in ranges

Task executed concurrently

Simple task that will request random numbers in range:

package com.farenda.java.util.concurrent;

import java.util.List;
import java.util.concurrent.Callable;

class ConcurrentRange implements Callable<List<Integer>> {

    private ConcurrentRandomNumbers generator;
    private final int from;
    private final int howMany;

    public ConcurrentRange(ConcurrentRandomNumbers generator,
                           int from, int howMany) {
        this.generator = generator;
        this.from = from;
        this.howMany = howMany;
    }

    @Override
    public List<Integer> call() throws Exception {
        // request random numbers for this thread:
        return generator.randomRange(from, howMany);
    }
}

Generate ranges of random numbers

We create three tasks to concurrently generate numbers in specified ranges and then just print the results:

package com.farenda.java.util.concurrent;

import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadLocalRandom;

import static java.util.Arrays.asList;
import static java.util.stream.Collectors.toList;

public class ConcurrentRandomNumbers {

    private List<Integer> randomRange(int from, int howMany) {
        return ThreadLocalRandom.current()
                .ints(howMany, from, from+howMany)
                .boxed()
                .collect(toList());
    }

    public static void main(String[] args) throws Exception {
        ConcurrentRandomNumbers generator = new ConcurrentRandomNumbers();

        ExecutorService es = Executors.newCachedThreadPool();

        List<ConcurrentRange> randomRanges = asList(
                new ConcurrentRange(generator, 10, 10),
                new ConcurrentRange(generator, 20, 10),
                new ConcurrentRange(generator, 30, 10));
        List<Future<List<Integer>>> results = es.invokeAll(randomRanges);

        for (Future<List<Integer>> future : results) {
            System.out.println("Range: " + future.get());
        }

        es.shutdown();
    }
}

Output of sample execution:

Range: [11, 16, 10, 10, 16, 13, 10, 11, 10, 18]
Range: [24, 25, 26, 22, 26, 26, 24, 29, 27, 24]
Range: [32, 30, 32, 30, 37, 31, 34, 30, 31, 36]
Share with the World!