【开源之夏】新增UUIDv7的生成器

This commit is contained in:
Looly 2024-09-29 09:27:25 +08:00
parent f0c591a1b1
commit 876a69e8c2
2 changed files with 18 additions and 16 deletions

View File

@ -185,18 +185,20 @@ public class UUID implements java.io.Serializable, Comparable<UUID> {
} }
/** /**
* 获取随机生成的UUIDv7 * 获取随机生成的UUIDv7<br>
* 开源之夏贡献内容https://gitee.com/dromara/hutool/pulls/1263
* *
* @return UUIDv7 * @return UUIDv7
* @author Cason(https://gitee.com/Casonhqc)
*/ */
public static UUID randomUUID7() { public static UUID randomUUID7() {
byte[] randomBytes = new byte[16]; final byte[] randomBytes = new byte[16];
final Random ng = Holder.NUMBER_GENERATOR; final Random ng = Holder.NUMBER_GENERATOR;
ng.nextBytes(randomBytes); ng.nextBytes(randomBytes);
long[] v7Time = getV7Time(); final long[] v7Time = getV7Time();
long milli = v7Time[0]; final long milli = v7Time[0];
long seq = v7Time[1]; final long seq = v7Time[1];
randomBytes[0] = (byte) (milli >> 40); randomBytes[0] = (byte) (milli >> 40);
randomBytes[1] = (byte) (milli >> 32); randomBytes[1] = (byte) (milli >> 32);
@ -208,20 +210,20 @@ public class UUID implements java.io.Serializable, Comparable<UUID> {
randomBytes[6] = (byte) ((0x70) | (0x0F & (seq >> 8))); randomBytes[6] = (byte) ((0x70) | (0x0F & (seq >> 8)));
randomBytes[7] = (byte) seq; randomBytes[7] = (byte) seq;
randomBytes[8] &= 0x3f; /* clear variant */ randomBytes[8] &= 0x3f; /* clear variant */
randomBytes[8] |= 0x80; /* set to IETF variant */ randomBytes[8] |= (byte) 0x80; /* set to IETF variant */
return new UUID(ByteUtil.toLong(randomBytes, 0, ByteOrder.BIG_ENDIAN), return new UUID(ByteUtil.toLong(randomBytes, 0, ByteOrder.BIG_ENDIAN),
ByteUtil.toLong(randomBytes, 8, ByteOrder.BIG_ENDIAN)); ByteUtil.toLong(randomBytes, 8, ByteOrder.BIG_ENDIAN));
} }
private static long[] getV7Time() { private static long[] getV7Time() {
long nano = System.nanoTime(); final long nano = System.nanoTime();
long milli = nano / NANOS_PER_MILLI; long milli = nano / NANOS_PER_MILLI;
long seq = (nano - milli * NANOS_PER_MILLI) >> 8; long seq = (nano - milli * NANOS_PER_MILLI) >> 8;
long now = (milli << 12) + seq; long now = (milli << 12) + seq;
while (true) { while (true) {
long last = lastV7time.get(); final long last = lastV7time.get();
if (now <= last) { if (now <= last) {
now = last + 1; now = last + 1;
milli = now >> 12; milli = now >> 12;

View File

@ -31,7 +31,6 @@ import org.junit.jupiter.api.Test;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
@ -79,7 +78,7 @@ public class IdUtilTest {
timer.start(); timer.start();
for (int i = 0; i < 1000000; i++) { for (int i = 0; i < 1000000; i++) {
//noinspection ResultOfMethodCallIgnored //noinspection ResultOfMethodCallIgnored
UUID.randomUUID().toString().replace("-", ""); java.util.UUID.randomUUID().toString().replace("-", "");
} }
timer.stop(); timer.stop();
Console.log(timer.getLastTaskTimeMillis()); Console.log(timer.getLastTaskTimeMillis());
@ -169,8 +168,8 @@ public class IdUtilTest {
@Test @Test
public void testUUIDv7Format() { public void testUUIDv7Format() {
org.dromara.hutool.core.data.id.UUID uuid = org.dromara.hutool.core.data.id.UUID.randomUUID7(); final org.dromara.hutool.core.data.id.UUID uuid = org.dromara.hutool.core.data.id.UUID.randomUUID7();
String uuidStr = uuid.toString(); final String uuidStr = uuid.toString();
// 验证UUID字符串格式是否符合标准 // 验证UUID字符串格式是否符合标准
assertTrue(uuidStr.matches("^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$")); assertTrue(uuidStr.matches("^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"));
@ -178,7 +177,7 @@ public class IdUtilTest {
@Test @Test
public void testUUIDv7Properties() { public void testUUIDv7Properties() {
org.dromara.hutool.core.data.id.UUID uuid = org.dromara.hutool.core.data.id.UUID.randomUUID7(); final org.dromara.hutool.core.data.id.UUID uuid = org.dromara.hutool.core.data.id.UUID.randomUUID7();
// 验证版本号是否为7 // 验证版本号是否为7
assertEquals(7, uuid.version()); assertEquals(7, uuid.version());
@ -190,11 +189,11 @@ public class IdUtilTest {
@RepeatedTest(10) @RepeatedTest(10)
public void testUUIDv7Uniqueness() { public void testUUIDv7Uniqueness() {
Set<org.dromara.hutool.core.data.id.UUID> uuids = new HashSet<>(); final Set<org.dromara.hutool.core.data.id.UUID> uuids = new HashSet<>();
// 生成100万个UUIDv7验证是否有重复 // 生成100万个UUIDv7验证是否有重复
for (int i = 0; i < 1000000; i++) { for (int i = 0; i < 1000000; i++) {
org.dromara.hutool.core.data.id.UUID uuid = org.dromara.hutool.core.data.id.UUID.randomUUID7(); final org.dromara.hutool.core.data.id.UUID uuid = org.dromara.hutool.core.data.id.UUID.randomUUID7();
assertFalse(uuids.contains(uuid)); assertFalse(uuids.contains(uuid));
uuids.add(uuid); uuids.add(uuid);
} }
@ -207,7 +206,7 @@ public class IdUtilTest {
// 验证连续生成的1000个UUIDv7是否呈单调递增趋势 // 验证连续生成的1000个UUIDv7是否呈单调递增趋势
for (int i = 0; i < 1000; i++) { for (int i = 0; i < 1000; i++) {
org.dromara.hutool.core.data.id.UUID next = org.dromara.hutool.core.data.id.UUID.randomUUID7(); final org.dromara.hutool.core.data.id.UUID next = org.dromara.hutool.core.data.id.UUID.randomUUID7();
assertTrue(next.compareTo(prev) > 0); assertTrue(next.compareTo(prev) > 0);
prev = next; prev = next;
} }
@ -217,6 +216,7 @@ public class IdUtilTest {
* UUIDv7的性能测试 * UUIDv7的性能测试
*/ */
@Test @Test
@Disabled
public void testUUIDv7Benchmark() { public void testUUIDv7Benchmark() {
final StopWatch timer = DateUtil.createStopWatch(); final StopWatch timer = DateUtil.createStopWatch();