java中ThreadLocalRandom的使用详解

在java中我们通常会需要使用到java.util.Random来便利的生产随机数。但是Random是线程安全的,如果要在线程环境中的话就有可能产生性能瓶颈。

我们以Random中常用的nextInt方法为例来具体看一下:

  public int nextInt() {
    return next(32);
  }

nextInt方法实际上调用了下面的方法:

  protected int next(int bits) {
    long oldseed, nextseed;
    AtomicLong seed = this.seed;
    do {
      oldseed = seed.get();
      nextseed = (oldseed * multiplier + addend) & mask;
    } while (!seed.compareAndSet(oldseed, nextseed));
    return (int)(nextseed >>> (48 - bits));
  }

从代码中我们可以看到,方法内部使用了AtomicLong,并调用了它的compareAndSet方法来保证线程安全性。所以这个是一个线程安全的方法。

其实在多个线程环境中,Random根本就需要共享实例,那么该怎么处理呢?

在JDK 7 中引入了一个ThreadLocalRandom的类。ThreadLocal大家都知道就是线程的本地变量,而ThreadLocalRandom就是线程本地的Random。

我们看下怎么调用:

ThreadLocalRandom.current().nextInt();

我们来为这两个类分别写一个benchMark测试:

public class RandomUsage {

  public void testRandom() throws InterruptedException {
    ExecutorService executorService=Executors.newFixedThreadPool(2);
    Random random = new Random();
    List<Callable<Integer>> callables = new ArrayList<>();
    for (int i = 0; i < 1000; i++) {
      callables.add(() -> {
        return random.nextInt();
      });
      }
    executorService.invokeAll(callables);
  }

  public static void main(String[] args) throws RunnerException {
    Options opt = new OptionsBuilder()
        .include(RandomUsage.class.getSimpleName())
        // 预热5轮
        .warmupIterations(5)
        // 度量10轮
        .measurementIterations(10)
        .forks(1)
        .build();

    new Runner(opt).run();
  }
}
public class ThreadLocalRandomUsage {

  @Benchmark
  @BenchmarkMode(Mode.AverageTime)
  @OutputTimeUnit(TimeUnit.MICROSECONDS)
  public void testThreadLocalRandom() throws InterruptedException {
    ExecutorService executorService=Executors.newFixedThreadPool(2);
    List<Callable<Integer>> callables = new ArrayList<>();
    for (int i = 0; i < 1000; i++) {
      callables.add(() -> {
        return ThreadLocalRandom.current().nextInt();
      });
      }
    executorService.invokeAll(callables);
  }

  public static void main(String[] args) throws RunnerException {
    Options opt = new OptionsBuilder()
        .include(ThreadLocalRandomUsage.class.getSimpleName())
        // 预热5轮
        .warmupIterations(5)
        // 度量10轮
        .measurementIterations(10)
        .forks(1)
        .build();

    new Runner(opt).run();
  }
}

分析运行结果,我们可以看出ThreadLocalRandom在多线程环境中会比Random要快。

本文的例子可以参考https://github.com/ddean2009/learn-java-concurrency/tree/master/ThreadLocalRandom

到此这篇关于java中ThreadLocalRandom的使用详解的文章就介绍到这了,更多相关java ThreadLocalRandom内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 浅谈Java引用和Threadlocal的那些事

    1 背景 某一天在某一个群里面的某个群友突然提出了一个问题:"threadlocal的key是虚引用,那么在threadlocal.get()的时候,发生GC之后,key是否是null?"屏幕前的你可以好好的想想这个问题,在这里我先卖个关子,先讲讲Java中引用和ThreadLocal的那些事. 2 Java中的引用 对于很多Java初学者来说,会把引用和对象给搞混淆.下面有一段代码, User zhangsan = new User("zhangsan", 24)

  • 快速了解Java中ThreadLocal类

    最近看Android FrameWork层代码,看到了ThreadLocal这个类,有点儿陌生,就翻了各种相关博客一一拜读:自己随后又研究了一遍源码,发现自己的理解较之前阅读的博文有不同之处,所以决定自己写篇文章说说自己的理解,希望可以起到以下作用: - 可以疏通研究结果,加深自己的理解: - 可以起到抛砖引玉的作用,帮助感兴趣的同学疏通思路: - 分享学习经历,同大家一起交流和学习. 一. ThreadLocal 是什么 ThreadLocal 是Java类库的基础类,在包java.lang下

  • Java ThreadLocal的设计理念与作用

    Java中的ThreadLocal类允许我们创建只能被同一个线程读写的变量.因此,如果一段代码含有一个ThreadLocal变量的引用,即使两个线程同时执行这段代码,它们也无法访问到对方的ThreadLocal变量. 如何创建ThreadLocal变量 以下代码展示了如何创建一个ThreadLocal变量: private ThreadLocal myThreadLocal = new ThreadLocal(); 我们可以看到,通过这段代码实例化了一个ThreadLocal对象.我们只需要实例

  • java线程封闭之栈封闭和ThreadLocal

    线程封闭 在多线程的环境中,我们经常使用锁来保证线程的安全,但是对于每个线程都要用的资源使用锁的话那么程序执行的效率就会受到影响,这个时候可以把这些资源变成线程封闭的形式. 1.栈封闭 所谓的栈封闭其实就是使用局部变量存放资源,我们知道局部变量在内存中是存放在虚拟机栈中,而栈又是每个线程私有独立的,所以这样可以保证线程的安全. 2.ThreadLocal 我们先看ThreadLocal和线程Thread的关系图. 再看下ThreadLocal的操作,以get为例 public T get() {

  • Java ThreadLocal类应用实战案例分析

    本文实例讲述了Java ThreadLocal类应用.分享给大家供大家参考,具体如下: 一 点睛 ThreadLocal,是Thread Local Variable(线程局部变量)的意思,也许将它命名为ThreadLocalVar更加合适. 线程局部变量(ThreadLocal)其实的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,使每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突.从线程的角度看,就好像每一个线程都完全拥有该变量. ThreadLocal类的

  • Java ThreadLocal用法实例详解

    本文实例讲述了Java ThreadLocal用法.分享给大家供大家参考,具体如下: 目录 ThreadLocal的基本使用 ThreadLocal实现原理 源码分析(基于openjdk11) get方法: setInitialValue方法 getEntry方法 set方法 ThreadLocalMap的set方法 replaceStaleEntry方法 cleanSomeSlots方法 rehash方法 expungeStaleEntries方法 resize方法 ThreadLocal实现

  • 深入学习java ThreadLocal的源码知识

    简介 ThreadLocal是每个线程自己维护的一个存储对象的数据结构,线程间互不影响实现线程封闭.一般我们通过ThreadLocal对象的get/set方法存取对象. 源码分析 ThreadLocal的set方法源码如下 public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); // 根据当前线程获得ThreadLocalMap对象 if (map != null)

  • java线程本地变量ThreadLocal详解

    介绍 ThreadLocal作为JDK1.2以来的一个java.lang包下的一个类,在面试和工程中都非常重要,这个类的主要目的是提供线程本地的变量,所以也有很多地方把这个类叫做线程本地变量 从字面理解,这个类为每个线程都创建了一个本地变量,实际上是ThreadLocal为变量在每个线程中都创建了一个副本,使得每个线程都可以访问自己内部的副本变量 通常提到多线程,都会考虑变量同步的问题,但是ThreadLocal并不是为了解决多线程共享变量同步的问题,而是为了让每个线程的变量不互相影响,相当于线

  • Java并发编程学习之ThreadLocal源码详析

    前言 多线程的线程安全问题是微妙而且出乎意料的,因为在没有进行适当同步的情况下多线程中各个操作的顺序是不可预期的,多线程访问同一个共享变量特别容易出现并发问题,特别是多个线程需要对一个共享变量进行写入时候,为了保证线程安全, 一般需要使用者在访问共享变量的时候进行适当的同步,如下图所示: 可以看到同步的措施一般是加锁,这就需要使用者对锁也要有一定了解,这显然加重了使用者的负担.那么有没有一种方式当创建一个变量的时候,每个线程对其进行访问的时候访问的是自己线程的变量呢?其实ThreaLocal就可

  • java中ThreadLocalRandom的使用详解

    在java中我们通常会需要使用到java.util.Random来便利的生产随机数.但是Random是线程安全的,如果要在线程环境中的话就有可能产生性能瓶颈. 我们以Random中常用的nextInt方法为例来具体看一下: public int nextInt() { return next(32); } nextInt方法实际上调用了下面的方法: protected int next(int bits) { long oldseed, nextseed; AtomicLong seed = t

  • Java中自动生成构造方法详解

    Java中自动生成构造方法详解 每个类在没有声明构造方法的前提下,会自动生成一个不带参数的构造方法,如果类一但声明有构造方法,就不会产生了.证明如下: 例1: class person { person(){System.out.println("父类-person");} person(int z){} } class student extends person { // student(int x ,int y){super(8);} } class Rt { public st

  • 基于Java中的StringTokenizer类详解(推荐)

    StringTokenizer是字符串分隔解析类型,属于:Java.util包. 1.StringTokenizer的构造函数 StringTokenizer(String str):构造一个用来解析str的StringTokenizer对象.java默认的分隔符是"空格"."制表符('\t')"."换行符('\n')"."回车符('\r')". StringTokenizer(String str,String delim)

  • JAVA中string数据类型转换详解

    在JAVA中string是final类,提供字符串不可以修改,string类型在项目中经常使用,下面给大家介绍比较常用的string数据类型转换: String数据类型转换成long.int.double.float.boolean.char等七种数据类型 复制代码 代码如下: * 数据类型转换 * @author Administrator * */ public class 数据类型转换 { public static void main(String[] args) { String c=

  • java 中 阻塞队列BlockingQueue详解及实例

    java 中 阻塞队列BlockingQueue详解及实例 BlockingQueue很好的解决了多线程中数据的传输,首先BlockingQueue是一个接口,它大致有四个实现类,这是一个很特殊的队列,如果BlockQueue是空的,从BlockingQueue取东西的操作将会被阻断进入等待状态,直到BlockingQueue进了东西才会被唤醒.同样,如果BlockingQueue是满的,任何试图往里存东西的操作也会被阻断进入等待状态,直到BlockingQueue里有空间才会被唤醒继续操作.

  • Java中BigDecimal的基本运算(详解)

    BigDecimal一共有4个够造方法,让来看看其中比较常用的两种用法: 第一种:BigDecimal(double val) Translates a double into a BigDecimal. 第二种:BigDecimal(String val) Translates the String repre sentation of a BigDecimal into a BigDecimal. 使用BigDecimal要用String来够造,要做一个加法运算,需要先将两个浮点数转为Str

  • java 中 ChannelHandler的用法详解

    java 中 ChannelHandler的用法详解 前言: ChannelHandler处理一个I/O event或者拦截一个I/O操作,在它的ChannelPipeline中将其递交给相邻的下一个handler. 通过继承ChannelHandlerAdapter来代替 因为这个接口有许多的方法需要实现,你或许希望通过继承ChannelHandlerAdapter来代替. context对象 一个ChannelHandler和一个ChannelHandlerContext对象一起被提供.一个

  • Java中的反射机制详解

    Java中的反射机制详解 反射,当时经常听他们说,自己也看过一些资料,也可能在设计模式中使用过,但是感觉对它没有一个较深入的了解,这次重新学习了一下,感觉还行吧! 一,先看一下反射的概念: 主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义. 反射是Java中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接.但是反射使用不当会成本很高! 看概念很晕的,继续往下

  • java 中匿名内部类的实例详解

    java 中匿名内部类的实例详解 原来的面貌: class TT extends Test{ void show() { System.out.println(s+"~~~哈哈"); System.out.println("超级女声"); } TT tt=new TT(); tt.show(); 只是说我们这里采用的是匿名的形式来处理. 重写了Test的show()方法,在重写好了以后,又调用了重写后的show()方法 实现代码: package cn.com; c

  • Java中isAssignableFrom的用法详解

    class1.isAssignableFrom(class2) 判定此 Class 对象所表示的类或接口与指定的 Class 参数所表示的类或接口是否相同,或是否是其超类或超接口.如果是则返回 true:否则返回 false.如果该 Class 表示一个基本类型,且指定的 Class 参数正是该 Class 对象,则该方法返回 true:否则返回 false. 1. class2是不是class1的子类或者子接口 2. Object是所有类的父类 一个例子搞定: package com.auuz

随机推荐