java并发编程之美第三章读书笔记

news2024/11/18 3:23:35

java并发包中ThreadLocalRandom类原理剖析

该ilei是JDK7在JUC包下面新增的随机数生成器吗,弥补了Random类在多线程下的缺陷

Random类及其局限性

public class RandomTest {
    public static void main(String[] args) {
        Random random=new Random();
        for (int i=0;i<10;i++){
            System.out.println(random.nextInt(5));
        }
    }
}

每个Random实例里面都有一个原子性的种子变量来记录当前的种子值,当要生成的随机数需要根据当前种子计算新的种子并更新回原子变量,在多线程下使用单个Random实例生成随机数时,当多个线程同时计算随机数来计算新的种子时,多个线程会竞争同一个原子变量的更新操作,由于原子变量的更新是CAS操作,同时只有一个线程会成功,所以造成大量线程进行自旋操作,这会降低并发性能

ThreadLocalRandom

public class ThreadLocalRandomTest {
    public static void main(String[] args) {
        ThreadLocalRandom random=ThreadLocalRandom.current();
        for (int i=0;i<10;i++){
            System.out.println(random.nextInt(5));
        }

    }
}

每个线程都维护一个种子变量,则每个变量生成随机数时候根据自己老的种子计算新的种子,并使用新种子更新老的种子,再根据种子计算随机数,就不会存在竞争问题,大大提高了高并发性能

源码分析

从图中可以看出ThreadLocalRandom类继承了Random 类并重写了nextlnt方法、在 ThreadLocalRandom 类中并没有使用继承自Random 类的原子性种子变量ThreadLocalRandom 中并没有存放具体的种子,具体的种子存放在具体的调用线程threadLocalRandomSeed 变量里面。ThreadLocalRandom 类似于 ThreadLocal 类,就是工具类。当线程调用 ThreadLocalRandom 的current 方法时,ThreadLocalRandom 负责初始调用线程的threadLocalRandomSeed 变量,也就是初始化种子。

当调用ThreadLocalRandom 的 nextInt方法时,实际上是获取当前线程threadLocalRandomSeed 变量作为当前种子来计算新的种子,然后更新新的种子到当前线程的threadLocalRandomSeed 变量,而后再根据新种子并使用具体算法计算随机数。这需要注意的是,threadLocalRandomSeed 变量就是 Thread 类里面的一个普通 long变量,它并不是原子性变量。其实道理很简单,因为这个变量是线程级别的,所以根本不需要使用

原子性变量,如果你还是不理解可以思考下 ThreadLocal 的原理其中 seeder 和 probeGenerator是两个原子性变量,在初始化调用线程的种子和探针变量时会用到它们,每个线程只会使用一次。

另外,变量instance 是 ThreadLocalRandom 的一个实例,该变量是 static 的。当多线程通过 ThreadLocalRandom 的 current 方法获取ThreadLocalRandom 的实例时,其实获取的是同一个实例。但是由于具体的种子是存放在线程里面的,所以在 ThreadLocalRandom的实例里面只包含与线程无关的通用算法,所以它是线程安全的

Unsafe机制

ThreadLocalRandom 的current()方法

该方法是获取ThreadLocalRandom实例,并初始化调用线程中的ThreadLocalRandomSeed和ThreadLocalRandomProbe变量

static final ThreadLocalRandom instance = new ThreadLocalRandom();
public static ThreadLocalRandom current() {
    if (UNSAFE.getInt(Thread.currentThread(), PROBE) == 0)
        localInit();
    return instance;
}
static final void localInit() {
        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);
    }

int nextInt(int bound)方法

public int nextInt(int bound) {
    if (bound <= 0)
        throw new IllegalArgumentException(BadBound);
    int r = mix32(nextSeed());
    int m = bound - 1;
    if ((bound & m) == 0) // power of two
        r &= m;
    else { // reject over-represented candidates
        for (int u = r >>> 1;
             u + m - (r = u % bound) < 0;
             u = mix32(nextSeed()) >>> 1)
            ;
    }
    return r;
}
final long nextSeed(){
    Thread t;
    long r;
    UNSAFE.putLong(t=Thread.currentThread(),SEED,r=UNSAFE.getLong(t,SEED)+GAMMA);
    return r; 
}

总结

首先讲解了Randon实现原理以及Random在多线程下需要竞争种子原子变量更新操作的缺点,从而引进ThreadLocalRandom类,该类使用ThreadLocal的原理,让每一个线程都持有一个本地的种子变量,该种子变量只有在使用随机数时候才会被初始化,在多线程下计算新种子是根据自己线程内维护的种子变量来进行更新,从而避免了竞争

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/492777.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Facebook 用户量十分庞大,为什么还使用 MySQL 数据库?

Facebook是一个拥有超30亿用户的互联网公司&#xff0c;拥有海量数据&#xff0c;而且增长很快&#xff0c;单机数据库完全无法满足这种需求。 这时需要对数据进行分片&#xff0c;存储到多个数据库节点中&#xff0c;这个时候如果使用IOE作为其中一个节点&#xff0c;肯定可以…

MySQL Order by对各种排序算法的应用

通常我们实现的排序算法&#xff0c;都是在”纯内存“环境中进行。 MySQL 作为数据库难道是在先将所有要排序的数据加载到内存&#xff0c;再应用排序算法吗&#xff1f; 一、什么是内排序&#xff1f;什么是外排序&#xff1f; 内排序&#xff1a;全称为内部排序。内部排序是…

力扣题库刷题笔记647-回文子串

1、题目如下&#xff1a; 2、个人Python代码实现 思路如下&#xff1a; a、以切片的形式&#xff0c;判断每个子字符串是否为回文字符串。这里如何确定切片的起始下标就很重要了 b、首先需要知道的是字符串s&#xff0c;s[i,j]&#xff0c;指的是从下标i开始&#xff0c;到下标…

cout源码浅析

目录 cout源码浅析 那么对于没有定义在这之中的要怎么办呢&#xff1f; 实际使用 结语 首先来看我从cplusplus中截取的这张图&#xff1a; 注意最下面这一行字。cout其实是ostream的一个标准对象object。而上面则演示了一些继承关系。 好的&#xff0c;理解了之后&#xf…

算法DAY52 动态规划10 300.最长递增子序列 674. 最长连续递增序列 718. 最长重复子数组

300.最长递增子序列 五部曲&#xff1a; 1、dp数组的含义&#xff1a; dp[ i ] : 代表 截至到nums[i] (包括 nums[i]) 的序列中&#xff0c;以nums[i] 结尾的&#xff0c;最长递增子序列的长度。这里强调以nums[i] 结尾&#xff0c;是因为还要跟nums[j]做对比&#xff0c;确定…

ACG-crcme1(★★★)

运行程序 info exit 查壳 没壳 载入OD分析 刚载入OD发现要使用 ACG.key 搜一下字符串看看 发现这有貌似成功相关的字符串 进去看看 可以找到关键跳 爆破的话直接在这就可以完成 上面就该是算法了 算法分析 开始先判断文件存在和文件内容大小 读取文件内容&am…

微前端 qiankun@2.10.5 源码分析(二)

微前端 qiankun2.10.5 源码分析&#xff08;二&#xff09; 我们继续上一节的内容。 loadApp 方法 找到 src/loader.ts 文件的第 244 行&#xff1a; export async function loadApp<T extends ObjectType>(app: LoadableApp<T>,configuration: FrameworkConfi…

uniapp - 实现微信小程序电子签名板,横屏手写姓名签名专用写字画板(详细运行示例,一键复制开箱即用)

效果图 实现了在uniapp项目中,微信小程序平台流畅的写字签名板(也可以绘图)功能源码,复制粘贴,改改样式几分钟即可搞定! 支持自动横屏、持预览,真机运行测试非常流畅不卡顿。 基础模板 如下代码所示。 <template><view class=

vue3.2+vite+vant4+sass搭建笔记

1、确定node版本 1、下载nvm安装包 官方下载地址&#xff1a;https://github.com/coreybutler/nvm-windows/releases 双击安装 2、在node官网下载安装多个node 3、切换node 2、创建项目 1、安装依赖 pnpm i 2、启动项目 npm run dev 3、配置指向src import { defineC…

FAST协议解析2 FIX Fast Tutorial翻译【PMap、copy操作符】

FIX Fast Tutorial FIX Fast教程 &#xff08;译注&#xff1a;本篇是对https://jettekfix.com/education/fix-fast-tutorial/翻译和解释&#xff0c;除了文本的直接翻译外&#xff0c;我还针对各点按我的理解进行了说明和验证&#xff0c;所以可以看到译文下会有很多译注&am…

虹科方案 | HK-Edgility:将 SASE 带到边缘

通过上期的文章&#xff0c;我们了解到虹科HK-Edgility软件系统《面向未来的安全SD-WAN》的解决方案。本篇文章&#xff0c;我们将带您了解虹科系统在SASE的方案简介。 一、时代背景 向软件即服务 (SaaS) 和云原生应用程序的过渡&#xff0c;加上越来越多的远程用户生成和访问公…

快来参与:2023全国大数据与计算智能挑战赛正在报名中

全国大数据与计算智能挑战赛是由国防科技大学系统工程学院大数据与决策实验室组织的年度赛事活动&#xff0c;旨在深入挖掘大数据应用实践中亟需破解的能力生成难题、选拔汇聚数据领域优势团队、促进大数据领域的技术创新和面向需求的成果生成、推动形成“集智众筹、联合攻关、…

Spring项目的创建与使用

一、创建Spring项目 这里使用Maven方式创建Spring项目&#xff0c;分为以下三步&#xff1a; 创建一个普通的Maven项目添加spring框架支持添加启动类 注&#xff1a;这里创建的是一个spring的core项目&#xff0c;不是web项目&#xff0c;只需要main方法&#xff0c;不需要t…

Ubuntu显示美化 优化 常用插件

Ubuntu显示美化 优化 常用插件 1. 安装 Extension Manager2. 网速显示&#xff08;不显示总流量记得关掉&#xff09;3. 顶部透明度4. 左侧dock导航透明度5. 过渡动画2022-01-22 毛玻璃效果 和 程序启动背景墙效果2022-01-23 窗口预览&#xff08;类windos多窗口&#xff09;20…

C++11实现线程池

1.所有权的传递 适用移动语义可以将一个unique_lock赋值给另一个unique_lock,适用move实现。 void myThread1() {unique_lock<mutex> myUnique (testMutex1,std::defer_lock);unique_lock<mutex>myUnique1(std::move(myUnique));//myUnique 则实效 myUnique1 相当…

在Linux中进行Jenkins部署(maven-3.9.1+jdk11)

Jenkins部署在公网IP为x.x.x.x的服务器上 maven-3.9.1要安装在jdk11环境中 环境准备 第一步&#xff0c;下载jdk-11.0.19_linux-x64_bin.tar.gz安装包。 登录地址&#xff1a;Java Downloads | Oracle 下载jdk-11.0.19_linux-x64_bin.tar.gz安装包&#xff0c;然后使用Win…

电子温湿度记录仪

电子温湿度记录仪&#xff1a;实时监测环境温度和湿度电子温湿度记录仪是一种用于实时监测环境温度和湿度的设备。它广泛应用于医疗、制药、食品加工、仓储、博物馆、实验室等领域&#xff0c;以确保环境温湿度处于合适的范围内&#xff0c;以保持物品和设备的稳定性和安全性。…

信号的产生——tripuls函数

信号的产生——tripuls函数, 功能&#xff1a;产生非周期三角波信号&#xff0c;其调用格式如下&#xff1a; &#xff08;1&#xff09;ytripuls(t)&#xff0c; &#xff08;2&#xff09;ytripuls(t,w)&#xff0c; &#xff08;3&#xff09;ytripuls(t,w,s)&#xff0…

Java多线程入门到精通学习大全?深入了解线程:生命周期、状态和优先级!(第二篇:线程的基础知识学习)

本文详细介绍了线程的基础知识&#xff0c;包括什么是线程、线程的生命周期、线程的状态和线程优先级等。在了解这些知识后&#xff0c;我们能够更好地掌握线程的使用方式&#xff0c;提高程序的并发性和效率。如果您对线程有更深入的问题&#xff0c;也欢迎向我们提问。 1. 什…

华为MPLS跨域——后门链路实验配置

目录 配置PE与CE设备对接命令&#xff08;通过OSPF对接&#xff09; 配置后门链路 可以使用任意方式来跑跨域MPLS&#xff08;A、B、C1、C2都可以&#xff09;&#xff0c;不过关于传递Vpnv4路由的配置此处不做介绍&#xff1b;此处只介绍关于PE和CE对接的配置和关于后门链路…