fix Snoefake bug

This commit is contained in:
Looly 2020-11-10 11:28:09 +08:00
parent e5574fa173
commit 6216eb9994
2 changed files with 36 additions and 11 deletions

View File

@ -33,11 +33,11 @@ public class Snowflake implements Serializable {
private final long twepoch;
private final long workerIdBits = 5L;
private final long dataCenterIdBits = 5L;
//// 最大支持机器节点数0~31一共32个
// 最大支持数据中心节点数0~31一共32个
// 最大支持机器节点数0~31一共32个
@SuppressWarnings({"PointlessBitwiseExpression", "FieldCanBeLocal"})
private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
private final long dataCenterIdBits = 5L;
// 最大支持数据中心节点数0~31一共32个
@SuppressWarnings({"PointlessBitwiseExpression", "FieldCanBeLocal"})
private final long maxDataCenterId = -1L ^ (-1L << dataCenterIdBits);
// 序列号12位
@ -48,8 +48,9 @@ public class Snowflake implements Serializable {
private final long dataCenterIdShift = sequenceBits + workerIdBits;
// 时间毫秒数左移22位
private final long timestampLeftShift = sequenceBits + workerIdBits + dataCenterIdBits;
@SuppressWarnings({"PointlessBitwiseExpression", "FieldCanBeLocal"})
private final long sequenceMask = -1L ^ (-1L << sequenceBits);// 4095
// 序列掩码用于限定序列最大值不能超过4095
@SuppressWarnings("FieldCanBeLocal")
private final long sequenceMask = ~(-1L << sequenceBits);// 4095
private final long workerId;
private final long dataCenterId;
@ -140,8 +141,8 @@ public class Snowflake implements Serializable {
*/
public synchronized long nextId() {
long timestamp = genTime();
if (timestamp < lastTimestamp) {
if(lastTimestamp - timestamp < 2000){
if (timestamp < this.lastTimestamp) {
if(this.lastTimestamp - timestamp < 2000){
// 容忍2秒内的回拨避免NTP校时造成的异常
timestamp = lastTimestamp;
} else{
@ -150,11 +151,12 @@ public class Snowflake implements Serializable {
}
}
if (timestamp == lastTimestamp) {
sequence = (sequence + 1) & sequenceMask;
if (timestamp == this.lastTimestamp) {
final long sequence = (this.sequence + 1) & sequenceMask;
if (sequence == 0) {
timestamp = tilNextMillis(lastTimestamp);
}
this.sequence = sequence;
} else {
sequence = 0L;
}

View File

@ -1,10 +1,17 @@
package cn.hutool.core.lang;
import java.util.HashSet;
import cn.hutool.core.collection.ConcurrentHashSet;
import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.thread.ConcurrencyTester;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.IdUtil;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import java.util.HashSet;
import java.util.Set;
/**
* Snowflake单元测试
* @author Looly
@ -43,4 +50,20 @@ public class SnowflakeTest {
Assert.assertEquals(2, idWorker.getDataCenterId(nextId));
Assert.assertTrue(idWorker.getGenerateDateTime(nextId) - System.currentTimeMillis() < 10);
}
@Test
@Ignore
public void uniqueTest(){
// 测试并发环境下生成ID是否重复
Snowflake snowflake = IdUtil.createSnowflake(0, 0);
Set<Long> ids = new ConcurrentHashSet<>();
ConcurrencyTester tester = ThreadUtil.concurrencyTest(100, () -> {
for (int i = 0; i < 5000; i++) {
if(false == ids.add(snowflake.nextId())){
throw new UtilException("重复ID");
}
}
});
}
}