java uuid和SecureRandom性能详解

1. java.security.SecureRandom源码分析

jdk产生uuid的代码:

public static UUID randomUUID() {

SecureRandom ng =Holder.numberGenerator;

byte[] randomBytes = newbyte[16];

ng.nextBytes(randomBytes);

randomBytes[6] &= 0x0f;  /* clear version       */

randomBytes[6]  |=0x40;  /* set to version 4     */

randomBytes[8] &= 0x3f;  /* clear variant       */

randomBytes[8]  |=0x80;  /* set to IETF variant  */

return newUUID(randomBytes);

}

使用了SecureRandom.next*的方法。

在使用SecureRandom产生下一个随机数的时候调用nextLong或者nextBytes,最终会调用SecureRandom的nextBytes。而nextBytes是一个同步方法,会产生性能瓶颈。

public long nextLong() {

// it‘s okay that the bottom wordremains signed.

return ((long)(next(32)) << 32)+ next(32);

}

final protected int next(int numBits) {

int numBytes = (numBits+7)/8;

byte b[] = new byte[numBytes];

int next = 0;

nextBytes(b);

for (int i = 0; i < numBytes; i++)

next = (next << 8)+ (b[i] & 0xFF);

return next >>> (numBytes*8 -numBits);

}

而nextBytes是一个同步的方法

synchronized public void nextBytes(byte[] bytes) {

secureRandomSpi.engineNextBytes(bytes);

}

secureRandomSpi被初始化为sun.security.provider.SecureRandom

secureRandomSpi是SecureRandom.NativePRNG的一个实例。从securityprovider列表中可以看到,SecureRandom.NativePRNG由sun.security.provider.NativePRNG提供服务。

Provider: Set SUN provider property[SecureRandom.NativePRNG/sun.security.provider.NativePRNG]

分析openjdk的源码可以看到,NativePRNG.engineNextBytes调用了NativePRNG.RandomIO.ensureBufferValid,而ensureBufferValid直接从urandom读取数据:

private void ensureBufferValid() throws IOException {
            ...
            readFully(urandomIn, urandomBuffer);
            ...
        }

通过测试可以发现,hotspot需要使用配置项"-Djava.security.egd=file:/dev/./urandom"才能从urandom读取数据,这里openjdk做了优化,直接从urandom读取数据。

2. JUG源码分析

JUG的com.fasterxml.uuid.impl.TimeBasedGenerator.generate()可以产生基于时间的UUID。由于在同步块中,仅做了整数的运算,因此,同步影响较小。

原理是在初始化的时候,根据网卡、随机数、计算出了一部分固定的数据:

public TimeBasedGenerator(EthernetAddress ethAddr , UUIDTimertimer)

{

byte [] uuidBytes = new byte [16];

if (ethAddr == null) {

ethAddr = EthernetAddress.constructMulticastAddress();

}

// initialize baseline with MAC address info

_ethernetAddress = ethAddr ;

_ethernetAddress .toByteArray(uuidBytes , 10);

// and add clock sequence

int clockSeq = timer.getClockSequence();

uuidBytes [UUIDUtil. BYTE_OFFSET_CLOCK_SEQUENCE] = ( byte )(clockSeq >> 8);

uuidBytes [UUIDUtil. BYTE_OFFSET_CLOCK_SEQUENCE+1] = ( byte) clockSeq ;

long l2 = UUIDUtil.gatherLong (uuidBytes , 8);

_uuidL2 = UUIDUtil.initUUIDSecondLong( l2);

_timer = timer ;

}

在调用generate的时候,根据当前时间,加上一个counter,生成另一半随机数:

public UUID generate()

{

final long rawTimestamp = _timer.getTimestamp ();

// Time field components are kind of shuffled, need toslice:

int clockHi = ( int) ( rawTimestamp >>> 32);

int clockLo = ( int) rawTimestamp ;

// and dice

int midhi = ( clockHi << 16) | ( clockHi >>>16);

// need to squeeze in type (4 MSBs in byte 6, clock hi)

midhi &= ~0xF000; // remove high nibble of 6th byte

midhi |= 0x1000; // type 1

long midhiL = ( long) midhi ;

midhiL = ((midhiL << 32) >>> 32); // to getrid of sign extension

// and reconstruct

long l1 = ((( long) clockLo ) << 32) | midhiL ;

// last detail: must force 2 MSB to be ‘10‘

return new UUID( l1, _uuidL2);

}

public final synchronized long getTimestamp ()

{

long systime = System.currentTimeMillis ();

......

_clockCounter &= 0xFF;

systime *= kClockMultiplierL;

systime += kClockOffset; //由于uuid需要GregorianCalendar,这里将1970年的时间加到系统时间

// Plus add the clock counter:

systime += _clockCounter ;

// and then increase

++ _clockCounter ;

return systime ;

}

时间: 2024-10-10 04:07:31

java uuid和SecureRandom性能详解的相关文章

Java虚拟机之垃圾回收详解一

Java虚拟机之垃圾回收详解一 Java技术和JVM(Java虚拟机) 一.Java技术概述: Java是一门编程语言,是一种计算平台,是SUN公司于1995年首次发布.它是Java程序的技术基础,这些程序包括:实用程序.游戏.商业应用程序.在全世界范围内,Java运行在超过数十亿台个人计算机上,数十亿台设备上,还包括手机和电视设备.Java由一系列的关键组件作为一个整体构建出了Java平台. Java Runtime Edition 当你下载Java,你就得到了Java运行环境(JRE).JR

java虚拟机启动参数分类详解

官方文档见: http://docs.sun.com/source/819-0084/pt_tuningjava.html java启动参数共分为三类:其一是标准参数(-),所有的JVM实现都必须实现这些参数的功能,而且向后兼容:其二是非标准参数(-X),默认jvm实现这些参数的功能,但是并不保证所有jvm实现都满足,且不保证向后兼容:其三是非Stable参数(-XX),此类参数各个jvm实现会有所不同,将来可能会随时取消,需要慎重使用: 一.标准参数中比较有用的: verbose -verbo

Java垃圾回收机制(GC)详解

Java垃圾回收机制(GC)详解 简介: 垃圾回收GC(Garbage Collection)是Java语言的核心技术之一,之前我们曾专门探讨过Java 7新增的垃圾回收器G1的新特性,但在JVM的内部运行机制上看,Java的垃圾回收原理与机制并未改变.垃圾收集的目的在于清除不再使用的对象.GC通过确定对象是否被活动对象引用来确定是否收集该对象.GC首先要判断该对象是否是时候可以收集.两种常用的方法是引用计数和对象引用遍历. 垃圾收集的算法分析: Java语言规范没有明确地说明JVM使用哪种垃圾

JAVA:23种设计模式详解(转)

设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代 码可靠性. 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样.项目中合理的运用 设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我

JAVA:23种设计模式详解(转)2

我们接着讨论设计模式,上篇文章我讲完了5种创建型模式,这章开始,我将讲下7种结构型模式:适配器模式.装饰模式.代理模式.外观模式.桥接模式.组合模式.享元模式.其中对象的适配器模式是各种模式的起源,我们看下面的图: 适配器模式将某个类的接口转换成客户端期望的另一个接口表示,目的是消除由于接口不匹配所造成的类的兼容性问题.主要分为三类:类的适配器模式.对象的适配器模式.接口的适配器模式.首先,我们来看看类的适配器模式,先看类图: 核心思想就是:有一个Source类,拥有一个方法,待适配,目标接口时

Java学习之道:详解Java解析XML的四种方法

XML现在已经成为一种通用的数据交换格式,它的平台无关性,语言无关性,系统无关性,给数据集成与交互带来了极大的方便.对于XML本身的语法知识与技术细节,需要阅读相关的技术文献,这里面包括的内容有DOM(Document Object Model),DTD(Document Type Definition),SAX(Simple API for XML),XSD(Xml Schema Definition),XSLT(Extensible Stylesheet Language Transform

Java网络编程和NIO详解5:Java 非阻塞 IO 和异步 IO

Java网络编程和NIO详解5:Java 非阻塞 IO 和异步 IO Java 非阻塞 IO 和异步 IO 转自https://www.javadoop.com/post/nio-and-aio 本系列文章首发于我的个人博客:https://h2pl.github.io/ 欢迎阅览我的CSDN专栏:Java网络编程和NIO https://blog.csdn.net/column/details/21963.html 部分代码会放在我的的Github:https://github.com/h2p

Java网络编程和NIO详解3:IO模型与Java网络编程模型

Java网络编程和NIO详解3:IO模型与Java网络编程模型 基本概念说明 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32次方).操作系统的核心是内核,独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件设备的所有权限.为了保证用户进程不能直接操作内核(kernel),保证内核的安全,操作系统将虚拟空间划分为两部分,一部分为内核空间,一部分为用户空间.针对linux操作系统而言,将最高的1G字节(从虚拟地址

Java网络编程和NIO详解开篇:Java网络编程基础

Java网络编程和NIO详解开篇:Java网络编程基础 计算机网络编程基础 转自:https://mp.weixin.qq.com/s/XXMz5uAFSsPdg38bth2jAA 我们是幸运的,因为我们拥有网络.网络是一个神奇的东西,它改变了你和我的生活方式,改变了整个世界. 然而,网络的无标度和小世界特性使得它又是复杂的,无所不在,无所不能,以致于我们无法区分甚至无法描述. 对于一个码农而言,了解网络的基础知识可能还是从了解定义开始,认识OSI的七层协议模型,深入Socket内部,进而熟练地