完成 ID 生成器的单元测试

unit-tests
ZhouXY108 2024-12-27 16:32:10 +08:00
parent 26bae49d47
commit 62e3769802
4 changed files with 107 additions and 48 deletions

View File

@ -1,6 +1,6 @@
[ ] 未开始测试 - 13 (19.40%)
[ ] 未开始测试 - 10 (14.93%)
[-] 测试未完成 - 9 (13.43%)
[Y] 测试完成 - 24 (35.82%)
[Y] 测试完成 - 27 (40.30%)
[x] 无需测试 - 21 (31.34%)
xyz.zhouxy.plusone.commons
@ -87,12 +87,12 @@ xyz.zhouxy.plusone.commons
DateTimeTools.java [-]
Enumeration.java [Y]
EnumTools.java [Y]
IdGenerator.java [ ]
IdWorker.java [ ]
IdGenerator.java [Y]
IdWorker.java [Y]
Numbers.java [Y]
OptionalTools.java [Y]
RandomTools.java [ ]
RegexTools.java [ ]
SnowflakeIdGenerator.java [ ]
SnowflakeIdGenerator.java [Y]
StringTools.java [Y]
TreeBuilder.java [Y]

View File

@ -64,9 +64,6 @@ public class SnowflakeIdGenerator {
/** 上次生成 ID 的时间截 */
private long lastTimestamp = -1L;
/** 锁对象 */
private final Object lock = new Object();
// ==============================Constructors=====================================
/**
@ -90,51 +87,47 @@ public class SnowflakeIdGenerator {
*
* @return SnowflakeId
*/
public long nextId() {
long timestamp;
synchronized (lock) {
timestamp = timeGen();
public synchronized long nextId() {
long timestamp = timeGen();
// 发生了回拨,此刻时间小于上次发号时间
if (timestamp < lastTimestamp) {
long offset = lastTimestamp - timestamp;
if (offset <= 5) {
// 时间偏差大小小于5ms则等待两倍时间
try {
TimeUnit.MILLISECONDS.sleep(offset << 1);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IllegalStateException(e);
}
timestamp = timeGen();
if (timestamp < lastTimestamp) {
// 还是小于,抛异常上报
throwClockBackwardsEx(lastTimestamp, timestamp);
}
} else {
// 发生了回拨,此刻时间小于上次发号时间
if (timestamp < lastTimestamp) {
long offset = lastTimestamp - timestamp;
if (offset <= 5) {
// 时间偏差大小小于5ms则等待两倍时间
try {
TimeUnit.MILLISECONDS.sleep(offset << 1);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IllegalStateException(e);
}
timestamp = timeGen();
if (timestamp < lastTimestamp) {
// 还是小于,抛异常上报
throwClockBackwardsEx(lastTimestamp, timestamp);
}
} else {
throwClockBackwardsEx(lastTimestamp, timestamp);
}
// 如果是同一时间生成的,则进行毫秒内序列
if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & SEQUENCE_MASK;
// 毫秒内序列溢出
if (sequence == 0) {
// 阻塞到下一个毫秒,获得新的时间戳
timestamp = tilNextMillis(lastTimestamp);
}
}
// 时间戳改变,毫秒内序列重置
else {
sequence = 0L;
}
// 上次生成 ID 的时间截
lastTimestamp = timestamp;
}
// 如果是同一时间生成的,则进行毫秒内序列
if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & SEQUENCE_MASK;
// 毫秒内序列溢出
if (sequence == 0) {
// 阻塞到下一个毫秒,获得新的时间戳
timestamp = tilNextMillis(lastTimestamp);
}
}
// 时间戳改变,毫秒内序列重置
else {
sequence = 0L;
}
// 上次生成 ID 的时间截
lastTimestamp = timestamp;
// 移位并通过或运算拼到一起组成64位的ID
return ((timestamp - TWEPOCH) << TIMESTAMP_LEFT_SHIFT) | datacenterIdAndWorkerId | sequence;
}

View File

@ -925,9 +925,10 @@ public class AssertToolsTests {
// #region - Condition
static final class MyException extends RuntimeException {}
@Test
void testCheckCondition() {
class MyException extends RuntimeException {}
AssertTools.checkCondition(true, MyException::new);

View File

@ -0,0 +1,65 @@
package xyz.zhouxy.plusone.commons.util;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.Test;
import cn.hutool.core.collection.ConcurrentHashSet;
public class IdGeneratorTests {
final ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
@Test
void testSnowflakeIdGenerator() { // NOSONAR
final SnowflakeIdGenerator snowflake = new SnowflakeIdGenerator(0, 0);
final Set<Long> ids = new ConcurrentHashSet<>();
for (int i = 0; i < 10000; i++) {
executor.execute(() -> {
for (int j = 0; j < 50000; j++) {
if (false == ids.add(snowflake.nextId())) {
throw new RuntimeException("重复ID");
}
}
});
}
}
@Test
void testIdWorker() { // NOSONAR
final IdWorker idWorker = new IdWorker(0L);
final Set<Long> ids = new ConcurrentHashSet<>();
for (int i = 0; i < 10000; i++) {
executor.execute(() -> {
for (int j = 0; j < 50000; j++) {
if (false == ids.add(idWorker.nextId())) {
throw new RuntimeException("重复ID");
}
}
});
executor.execute(() -> {
for (int j = 0; j < 50000; j++) {
if (false == ids.add(IdGenerator.nextSnowflakeId(0))) {
throw new RuntimeException("重复ID");
}
}
});
}
}
@Test
void testToSimpleString() {
UUID id = UUID.randomUUID();
assertEquals(id.toString().replaceAll("-", ""),
IdGenerator.toSimpleString(id));
}
}