安庆大理运城常德铜陵江西
投稿投诉
江西南阳
嘉兴昆明
铜陵滨州
广东西昌
常德梅州
兰州阳江
运城金华
广西萍乡
大理重庆
诸暨泉州
安庆南充
武汉辽宁

惊艳面试官Java中关于随机数生成8种方式的思考

8月24日 枯心人投稿
  Java中生成随机数常用的有下面这8种写法:简而言之,名称带安全的未必安全,名字简洁的未必简单。Math。random()RandomThreadLocalRandomSecureRandomUUID。randomUUID()RandomStringUtilsRandomUtilsRandomUtil
  Math。random()
  Talkischeap,showmethecode。先上源码:publicstaticdoublerandom(){returnRandomNumberGeneratorHolder。randomNumberGenerator。nextDouble();}privatestaticfinalclassRandomNumberGeneratorHolder{staticfinalRandomrandomNumberGeneratornewRandom();}
  从源码可以看出:Math。random本质上用的就是newRandom。而且人家给了一个最佳实践:使用的时候不用每次就new一个对象,直接做成一个静态类就可以了。
  Random
  Random是伪随机数类,采用线性同余算法产生的。伪随机数是1946年冯诺依曼提出来的。他在参加一个氢弹的制造项目,需要大量的随机数模拟核聚变、核裂变。因为当时设备没办法去存储大量的随机数,所以就想到了这个办法。伪随机数(或称伪乱数)这个称呼是因为真随机数都不是计算出来的。这里是使用一个确定性的算法计算出来的似乎是随机的数序,因此伪随机数实际上并不随机。从更宏大的视角看来,是非常有规律的,就像我在《大话高可用》里提到的炊烟。
  下面来说说这个线性同余算法,大家不用担心。我比大家还对算法一窍不通。但是我有人类的常识,这个常识是什么呢?既然是计算得到的,并且人类看起来没有规律,那一定有一个外部因子(种子),种子是一个变量。顺着这个思路看源码:Createsanewrandomnumbergenerator。Thisconstructorsetstheseedoftherandomnumbergeneratortoavalueverylikelytobedistinctfromanyotherinvocationofthisconstructor。publicRandom(){this(seedUniquifier()System。nanoTime());}
  没想到在构造函数里就给出了答案,这个因子就是系统时间,精确到纳秒。这里为了方便描述,我们举例想要一个int类型的随机数(实际它可以产生其他数值类型的随机数)。来看看源码:publicintnextInt(){returnnext(32);}protectedintnext(intbits){longoldseed,AtomicLongseedthis。do{oldseedseed。get();nextseed(oldseedmultiplieraddend)}while(!seed。compareAndSet(oldseed,nextseed));return(int)(nextseed(48bits));}
  解释一下:调用nextInt默认会生成32个比特位的数字。调用next方法,会有oldseed和nextseed。计算出nextseed会使CAS,将nextseed替换现有oldseed。nextseed的计算方法是oldseed做一些运算,运算的其他数值都是常量。最终返回nextseed值。
  因为使用了AtomicLong、自旋CAS(可以参考《系统梳理一下锁》),所以Random生成随机数是线程安全的。new一个全局变量,下次不用新建,Math。random的调用方法是合理的。
  通过这个源码大胆猜测一下:如果两个不同的进程或者线程,在纳秒级相同的时间同时调用newRandom,这时候nextInt的返回值是相同的!下次调用nextInt的值也相同!想要验证的话,可以下载java源码,在newRandom的地方稍作修改,
  System。nanoTime()改成固定值,这里我就不验证了。
  ThreadLocalRandom
  上面提到Random使用了线程安全的算法:AtomicLong、自旋CAS。这在保证线程安全的同时造成了很大的性能开销。ThreadLocalRandom是JDK7之后提供并发产生随机数,能够解决多个线程发生的竞争。
  它不是直接用new实例化,而是第一次使用时初始化其静态方法current()。直接调用静态方法,可以每个线程实例化一个。有朋友测试过,100个线程的情况下,3分钟,Math。random可以跑几百次。而
  ThreadLocalRandom。current()。nextInt()可以跑十几万次!
  来看一下它是怎么做到的:publicstaticThreadLocalRandomcurrent(){if(UNSAFE。getInt(Thread。currentThread(),PROBE)0)localInit();}staticfinalvoidlocalInit(){intpprobeGenerator。addAndGet(PROBEINCREMENT);intprobe(p0)?1:p;skip0longseedmix64(seeder。getAndAdd(SEEDERINCREMENT));ThreadtThread。currentThread();UNSAFE。putLong(t,SEED,seed);UNSAFE。putInt(t,PROBE,probe);}
  简而言之,Random是通过系统时间这个外部因子,而ThreadLocalRandom都是通过UNSAFE调用本地方法拿到线程本身的一些变量作为外部因子。所有的参数绑定在线程本身,和其他线程没有竞争,所以可以不加锁就保证线程安全。
  publicintnextInt(){returnmix32(nextSeed());}privatestaticintmix32(longz){z(z(z33))0xff51afd7ed558ccdL;return(int)(((z(z33))0xc4ceb9fe1a85ec53L)32);}finallongnextSeed(){TreadandupdateperthreadseedUNSAFE。putLong(tThread。currentThread(),SEED,rUNSAFE。getLong(t,SEED)GAMMA);}
  生成随机数计算的时候也都是调用线程内的变量,不加锁。大家可以举一反三一下,回忆一下ThreadLocal相关知识。
  SecureRandom
  在安全应用场景,随机数应该使用安全的随机数。密码学意义上的安全随机数,要求必须保证其不可预测性。
  由于Random是采用时间作为随机数种子,如果黑客知道随机数产生的时间,那就能重现随机数。而SecureRandom属于强随机数,一般不单独采用时间作为随机数种子,除了系统时间,还会采用临时文件夹中大小、某个线程从休眠到被唤醒所耗的时间等等一系列无法重现的值作为随机数种子。
  因为SecureRandom采用了很多外部参数,会产生熵源不足时阻塞问题。在我做过的项目中,因为有的业务凌晨没有流量,这个问题实际发生过。建议有明显低谷的业务,低谷时低于1TPS时不要用。
  像SecureRandom这种强随机在很多场景下效果不一定好。有一个小故事说itunes之前播歌的时候采用的是真随机。有些用户总是抱怨说你这是真随机吗?怎么来来回回给我播放那几首歌。苹果公司有苦说不出,于是把算法改成伪随机:洗牌算法,先把所有的歌打乱顺序,然后按顺序播放。改完之后用户纷纷点赞。
  适合使用SecureRandom的场景,比如要给每个资源生成一个url,为了防止url规律被别人攻破,使用爬虫爬取到自己的资源可以用这个。
  UUID。randomUUID()
  看下面的代码就知道UUID。randomUUID()是基于SecureRandompublicstaticUUIDrandomUUID(){SecureRandomngHolder。numberGbyte〔〕randomBytesnewbyte〔16〕;ng。nextBytes(randomBytes);randomBytes〔6〕0x0f;clearversionrandomBytes〔6〕0x40;settoversion4randomBytes〔8〕0x3f;clearvariantrandomBytes〔8〕0x80;settoIETFvariantreturnnewUUID(randomBytes);}
  有的朋友说不对呀,网上告诉我UUID是时间戳时钟序列MAC地址。注意上面代码注释有个settoversion4。
  从UUID的类注释里就可以看到java8提到4个版本:Theversionfieldholdsavaluethatdescribesthetypeofthis{codeUUID}。TherearefourdifferentbasictypesofUUIDs:timebased,DCEsecurity,namebased,andrandomlygeneratedUUIDs。Thesetypeshaveaversionvalueof1,2,3and4,respectively。
  翻译一下:
  版本1基于时间
  版本2基于DCEsercrity
  版本3基于名字(MD5)
  版本4基于随机数
  记住啦:java默认UUID是基于随机数的!
  证明一下:如果是基于时间戳的,生成的UUID前几位应该相同Testpublicvoidtest(){for(inti0;i3;i){System。out。println(UUID。randomUUID());}}
  结果:
  a0858771c9034061ba6a53efc372d8a0
  17ebdc58db6c452f9b21b4f54d3958a5
  116d6a4fe50a4001b94c61596da3a75d
  事实胜于记忆中的知识,它有可能是错的!
  javaUUID也支持版本3:Testpublicvoidtest(){for(inti0;i3;i){System。out。println(UUID。nameUUIDFromBytes(编程一生。getBytes()));}}
  运行结果:
  743f24b20914363bace1f4da750dccad
  743f24b20914363bace1f4da750dccad
  743f24b20914363bace1f4da750dccad
  这个在你的机器上执行也是这个结果,就是MD5了一下。
  有人说版本1、版本2怎么用,好像还听说过版本5。可以用linux命令
  uuidn3v1
  运行结果:
  5b01cea2956111e9965ba3d050dd0f23
  5b01cf60956111e9965c1b66505f5845
  5b01d118956111e9965d97354eb9e914
  linux命令版本可指定!
  RandomStringUtils、RandomUtils和RandomUtil
  这两个不是Java原生的方法,apachecommons下有这两个工具类,本质上还是Random。跟进代码去看可以发现:RandomUtils用的是JVMRandom。这个只不过是封装了一个静态的Random,所有使用RandomUtils类的,全局只用一个,减少了新建对象成本。
  如果你问我一般情况下建议用哪个,我选ThreadLocalRandom。那这么好的方法是不是应该也有对应的封装工具类呢?有的,hultool就搞了一个RandomUtil,
  RandomUtil。getRandom()返回的就是ThreadLocalRandom。
  RandomUtil。getSecureRandom()返回的是SecureRandom,提供多种选择。
  总结
  一张图表示他们之间的关系:
  在《CURD系统怎么做出技术含量怎样引导面试》里我提到可以利用工作中总结的技巧惊艳面试官,如果能把一个问题系统性讲明白,甚至让面试官意识到之前的知识竟然是错的,也一定能让面试官眼前一亮。
  原文链接:https:mp。weixin。qq。coms9ReYiLCyvJKPXK07fXmrvg
投诉 评论 转载

迄今为止最便宜的JasperLake迷你电脑JK01,起价1文章来源:迄今为止最便宜的JasperLake迷你电脑JK01,起价140美元CNXSoftware中文站今年年初的时候,IntelJasperLakeN系列的赛扬和奔腾……占山为王到互联互通大厂围墙怎么破疯传多日的9月17日前互联网平台要解除屏蔽网址链接一事有了官方口径。9月13日,工信部新闻发言人、信息通信管理局局长赵志国在国新办新闻发布会上表示,屏蔽网址链接是互联网行业专项……半导体公司PK江丰电子对战有研新材半导体芯片公司PK:江丰电子对战有研新材这两家公司到底谁最牛?牛到哪?1、靶材PK江丰电子:走出国门,进入一流厂商有研新材:国内一流厂商2、精密设……惊艳面试官Java中关于随机数生成8种方式的思考Java中生成随机数常用的有下面这8种写法:简而言之,名称带安全的未必安全,名字简洁的未必简单。Math。random()RandomThreadLocalRandomSecu……华为手机2022年04月04日新消息华为手机华为手机2022年04月04日新消息作为一名普通的数码爱好者客观来谈华为手机的现状和发展前景国内手机厂商都这么内卷了为什么却没有拿下华为的……一文掌握SQL基础前言知识无底,学海无涯,知识点虽然简单,但是比较多,所以将MySQL的基础写出来,方便自己以后查找,还有就是分享给大家。一、SQL简述1。SQL的概述Structu……未来充电桩前景广阔?2022年中国新基建研究报告出炉十四五规划提出:系统布局新型基础设施,加快第五代移动通信、工业互联网、大数据中心等建设。新基建具有强外部性、效用外溢性、公共产品属性、受益范围广、规模经济等特点,其基础性地位决……11月25日股市内参一、投资资讯1、工信部:将启动《乘用车企业平均燃料消耗量与新能源汽车积分并行管理办法》修订工作工业和信息化部装备工业一司日前会同财政部、商务部、海关总署、市场监管总……非典型理工男深耕行业13年陈博让救援英雄成为游戏主角非典型理工男深耕行业13年陈博:让救援英雄成为游戏主角华西都市报封面新闻记者朱珠热爱冒险,喜欢独处,遇事沉着冷静,这个非典型理工男陈博是一家游戏公司的创始人,而他做……西屋与宫和的颈椎按摩器,哪个好?各有好处吧,之前知道西屋与宫和,是因为他们两家生产的按摩椅,体验过还可以,后面在京东也看到了他们的颈椎按摩器,就分别买了一台家里人用。西屋与宫和的颈椎按摩仪都是机械式揉捏的,机……为什么地球上的动植物有公有母,这是巧合吗?不是巧合。动物中有如黄蟮、蜗牛等雌雄同体(自行转换)的存在。还有很多连性别区分都没有的动植物,通过自我分裂进行繁殖。那么为什么有些生物要分出两性,有些则不分呢……宁德时代市值破万亿等于比亚迪长城上汽之和中国股市中市值超过万亿的上市公司没几家,主要是茅台、工行、招行及农行,创业板还没有万亿企业,直到今天创业板一哥宁德时代突破万亿市值。5月31日,宁德时代开盘大涨5,股价逼……
音箱话筒CE检测认证办理流程小米瀑布屏手机专利出炉,小米11沦为牺牲品跌至大米价成弃机根本就没有128G这么大内存的手机IPO后,泡泡玛特应该NFT化Meta开发AI超级计算机,也许能成为世界最快小米投资生态独角兽,吊打外资,角逐海外103国市场,什么来头京东和B站都把裁员统称为毕业?移动手机行业2018年创造11,000亿美元经济量贡献4。6为什么大家开始反感联想和柳传志?数字货币发展的中国机遇与中国方案基于党的十九届五中全会的政策iOS15成照妖镜App过度收集用户信息何时休国家重点项目京津冀大数据基地一期送电两项通知下发,洋学历走向末路,留学生遇寒冬?家长难接受迷你世界虚空幻影BOSS重磅来袭,迷你大陆需要你来守护微信如何一次性多发几张图片呢?妊娠造句用妊娠造句大全衣柜书柜的组合设计古诗词教改小学必读首古诗词精讲苏猪大肠怎么清洗比较干净猪大肠清洗方法最喜欢玩性虐待的女生冬暖单打造句用单打造句大全世界上最大的青蛙:非洲巨蛙重3千克长30厘米(婴儿大小)macbook怎么分屏

友情链接:中准网聚热点快百科快传网快生活快软网快好知文好找七猫云易事利