com.github.azbh111.utils.java.uid.DefaultUidGenerator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of utils-java Show documentation
Show all versions of utils-java Show documentation
com.github.azbh111:utils-java
The newest version!
package com.github.azbh111.utils.java.uid;
import com.github.azbh111.utils.java.date.DateUtils;
import com.github.azbh111.utils.java.datetime.DateTimeUtils;
import java.time.LocalDate;
import java.util.Date;
import java.util.concurrent.TimeUnit;
/**
* @author: zyp
* @date: 2020/8/24 4:51 下午
*/
public class DefaultUidGenerator implements UidGenerator {
/**
* Customer epoch, unit as second. For example 2016-05-20 (ms: 1463673600000)
*/
// 起始时间
protected long epochSeconds = TimeUnit.MILLISECONDS.toSeconds(1463673600000L);
/**
* Stable fields after spring bean initializing
*/
protected BitsAllocator bitsAllocator;
protected long workerId;
/**
* Volatile fields caused by nextId()
*/
protected long sequence = 0L;
protected long lastSecond = -1L;
@Override
public long getUID() throws UidGenerateException {
try {
return nextId();
} catch (Exception e) {
throw new UidGenerateException(e);
}
}
@Override
public String parseUID(long uid) {
long totalBits = BitsAllocator.TOTAL_BITS;
long signBits = bitsAllocator.getSignBits();
long timestampBits = bitsAllocator.getTimestampBits();
long workerIdBits = bitsAllocator.getWorkerIdBits();
long sequenceBits = bitsAllocator.getSequenceBits();
// parse UID
long sequence = (uid << (totalBits - sequenceBits)) >>> (totalBits - sequenceBits);
long workerId = (uid << (timestampBits + signBits)) >>> (totalBits - workerIdBits);
long deltaSeconds = uid >>> (workerIdBits + sequenceBits);
Date thatTime = new Date(TimeUnit.SECONDS.toMillis(epochSeconds + deltaSeconds));
String thatTimeStr = DateTimeUtils.format(thatTime, "yyyy-MM-dd HH:mm:ss");
// format as string
return String.format("{\"UID\":\"%d\",\"timestamp\":\"%s\",\"workerId\":\"%d\",\"sequence\":\"%d\"}",
uid, thatTimeStr, workerId, sequence);
}
/**
* Get UID
*
* @return UID
* @throws UidGenerateException in the case: Clock moved backwards; Exceeds the max timestamp
*/
protected synchronized long nextId() {
long currentSecond = getCurrentSecond();
// Clock moved backwards, refuse to generate uid
if (currentSecond < lastSecond) {
long refusedSeconds = lastSecond - currentSecond;
throw new UidGenerateException("Clock moved backwards. Refusing for %d seconds", refusedSeconds);
}
// At the same second, increase sequence
if (currentSecond == lastSecond) {
sequence = (sequence + 1) & bitsAllocator.getMaxSequence();
// Exceed the max sequence, we wait the next second to generate uid
if (sequence == 0) {
currentSecond = getNextSecond(lastSecond);
}
// At the different second, sequence restart from zero
} else {
sequence = 0L;
}
lastSecond = currentSecond;
// Allocate bits for UID
return bitsAllocator.allocate(currentSecond - epochSeconds, workerId, sequence);
}
/**
* Get next millisecond
*/
private long getNextSecond(long lastTimestamp) {
long timestamp = getCurrentSecond();
while (timestamp <= lastTimestamp) {
timestamp = getCurrentSecond();
}
return timestamp;
}
/**
* Get current second
*/
private long getCurrentSecond() {
long currentSecond = System.currentTimeMillis() / 1000;
if (currentSecond - epochSeconds > bitsAllocator.getMaxDeltaSeconds()) {
throw new UidGenerateException("Timestamp bits is exhausted. Refusing UID generate. Now: " + currentSecond);
}
return currentSecond;
}
public static class DefaultUidGeneratorBuilder {
/**
* Bits allocate
*/
private int timeBits = 28;
private int workerBits = 22;
private int seqBits = 13;
// 起始日期 2020-01-01
private LocalDate epochSecondsStart = LocalDate.of(2020, 1, 1);
private long workerId;
public UidGenerator build() {
DefaultUidGenerator g = new DefaultUidGenerator();
if (timeBits + workerBits + seqBits > 63) {
throw new UidGenerateException("bits can not be greater than 63");
}
if (timeBits + workerBits + seqBits < 63) {
// 自动设置timeBits
timeBits = 63 - workerBits - seqBits;
}
g.bitsAllocator = new BitsAllocator(timeBits, workerBits, seqBits);
g.epochSeconds = DateUtils.toDate(epochSecondsStart).getTime() / 1000;
g.workerId = workerId;
return g;
}
/**
* 设置最大节点数
*
* @param maxIds
* @return
*/
public DefaultUidGeneratorBuilder setMaxWorkers(int maxWorkers) {
int bits = 1;
while ((1 << bits) - 1 < maxWorkers) {
bits++;
}
this.workerBits = bits;
return this;
}
/**
* 每秒能生成的id数
*
* @param maxIds
* @return
*/
public DefaultUidGeneratorBuilder setMaxIdInSeconds(int maxIds) {
int bits = 1;
while ((1 << bits) - 1 < maxIds) {
bits++;
}
this.seqBits = bits;
return this;
}
public DefaultUidGeneratorBuilder setTimeBits(int timeBits) {
this.timeBits = timeBits;
return this;
}
public DefaultUidGeneratorBuilder setWorkerBits(int workerBits) {
this.workerBits = workerBits;
return this;
}
public DefaultUidGeneratorBuilder setSeqBits(int seqBits) {
this.seqBits = seqBits;
return this;
}
public DefaultUidGeneratorBuilder setEpochSecondsStart(LocalDate epochSecondsStart) {
this.epochSecondsStart = epochSecondsStart;
return this;
}
public DefaultUidGeneratorBuilder setWorkerId(long workerId) {
this.workerId = workerId;
return this;
}
public int getTimeBits() {
return timeBits;
}
public int getWorkerBits() {
return workerBits;
}
public int getSeqBits() {
return seqBits;
}
public LocalDate getEpochSecondsStart() {
return epochSecondsStart;
}
public long getWorkerId() {
return workerId;
}
}
public static DefaultUidGeneratorBuilder builder() {
return new DefaultUidGeneratorBuilder();
}
}