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

View File

@ -1,10 +1,17 @@
package cn.hutool.core.lang; 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.Assert;
import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import java.util.HashSet;
import java.util.Set;
/** /**
* Snowflake单元测试 * Snowflake单元测试
* @author Looly * @author Looly
@ -43,4 +50,20 @@ public class SnowflakeTest {
Assert.assertEquals(2, idWorker.getDataCenterId(nextId)); Assert.assertEquals(2, idWorker.getDataCenterId(nextId));
Assert.assertTrue(idWorker.getGenerateDateTime(nextId) - System.currentTimeMillis() < 10); 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");
}
}
});
}
} }