package rocks.inspectit.agent.java.sdk.opentracing.internal.util; import java.lang.reflect.Field; import java.util.Random; import rocks.inspectit.agent.java.sdk.opentracing.internal.TracerLogger; import rocks.inspectit.agent.java.sdk.opentracing.internal.impl.TracerLoggerWrapper; /** * Helper class for generating random numbers needed for the tracing. Currently works with * {@link java.util.concurrent.ThreadLocalRandom} if java version is 1.7 and higher, as it's * expected that there is contention when creating ids. If we are in Java 6 we'll use normal random * that is thread-safe but can be slower. * * @author Ivan Senic * */ @SuppressWarnings("unchecked") public final class RandomUtils { /** * {@link TracerLogger} of this class. */ private static final TracerLogger LOGGER = TracerLoggerWrapper.getTraceLogger(RandomUtils.class); /** * Random to use. */ private static final Random RANDOM = new Random(); /** * LocalRandom field in the java.util.concurrent.ThreadLocalRandom class. */ private static ThreadLocal<Random> threadLocalRandomLocal; static { // try to load thread local random try { Class<?> clazz = Class.forName("java.util.concurrent.ThreadLocalRandom"); Field field = clazz.getDeclaredField("localRandom"); field.setAccessible(true); threadLocalRandomLocal = (ThreadLocal<Random>) field.get(null); } catch (Exception e) { if (LOGGER.isInfoEnabled()) { LOGGER.info("ThreadLocalRandom is not available. Using " + RANDOM.getClass().getSimpleName() + " for generating random numbers."); } } } /** * Private constructor. */ private RandomUtils() { } /** * Returns the random long number. Unlike {@link Random#nextLong()} method, this utility method * may return all possible long values (64-bit spread, compared to 48-bit spread defined by the * {@link Random} interface). * * @return Random long number, based on the {@link Random} returned by the {@link #getRandom()}. */ public static long randomLong() { byte[] randomBytes = new byte[8]; getRandom().nextBytes(randomBytes); //@formatter:off return ((randomBytes[0] & 0xffL) << 56) | ((randomBytes[1] & 0xffL) << 48) | ((randomBytes[2] & 0xffL) << 40) | ((randomBytes[3] & 0xffL) << 32) | ((randomBytes[4] & 0xffL) << 24) | ((randomBytes[5] & 0xffL) << 16) | ((randomBytes[6] & 0xffL) << 8) | (randomBytes[7] & 0xffL); //@formatter:on } /** * Returns random to use when generating random ids. * * @return Returns random to use when generating random ids. */ private static Random getRandom() { if (null != threadLocalRandomLocal) { return threadLocalRandomLocal.get(); } return RANDOM; } }