全局唯一,自增,Long类型
1.自定义一个SystemClock
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
public class SystemClock {
private final long period;
private final AtomicLong now;
private SystemClock(long period) {
this.period = period;
this.now = new AtomicLong(System.currentTimeMillis());
scheduleClockUpdating();
}
/**
* 尝试下枚举单例法
*/
private enum SystemClockEnum {
SYSTEM_CLOCK;
private SystemClock systemClock;
SystemClockEnum() {
systemClock = new SystemClock(1);
}
public SystemClock getInstance() {
return systemClock;
}
}
/**
* 获取单例对象
* @return com.cmallshop.module.core.commons.util.sequence.SystemClock
*/
private static SystemClock getInstance() {
return SystemClockEnum.SYSTEM_CLOCK.getInstance();
}
/**
* 获取当前毫秒时间戳
* @return long
*/
public static long now() {
return getInstance().now.get();
}
/**
* 起一个线程定时刷新时间戳
*/
private void scheduleClockUpdating() {
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(runnable -> {
Thread thread = new Thread(runnable, "System Clock");
thread.setDaemon(true);
return thread;
});
scheduler.scheduleAtFixedRate(() -> now.set(System.currentTimeMillis()), period, period, TimeUnit.MILLISECONDS);
}
}
2.创建分布式id生产工具类
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.SystemUtils;
import java.net.Inet4Address;
import java.net.UnknownHostException;
/**
* @author hc
* @date 2022/11/9 16:12
* @desc
*/
@Slf4j
public class SequenceUtils {
/**
* 初始偏移时间戳 1640966400L
*/
private static final long OFFSET = 1652343192L;
/**
* 机器id (0~31 保留 32~63作为备份机器)
*/
private static long WORKER_ID = 0;
/**
* 机器id所占位数 (5bit, 支持最大机器数 2^5 = 32)
*/
private static final long WORKER_ID_BITS = 6L;
/**
* 数据中心id (0~15)
*/
private static long DATACENTER_ID = 0;
/**
* 数据中心所占位数 (5bit, 支持最大数据中心数 2^5 = 32)
*/
private static final long DATACENTER_ID_BITS = 4L;
/**
* 自增序列所占位数 (11bit, 支持最大每秒生成 2^11 = 2048)
*/
private static final long SEQUENCE_ID_BITS = 11L;
/**
* 机器id偏移位数
*/
private static final long WORKER_SHIFT_BITS = SEQUENCE_ID_BITS;
/**
* 机器id偏移位数
*/
private static final long DATACENTER_SHIFT_BITS = SEQUENCE_ID_BITS + WORKER_ID_BITS;
/**
* 自增序列偏移位数
*/
private static final long OFFSET_SHIFT_BITS = SEQUENCE_ID_BITS + WORKER_ID_BITS + DATACENTER_ID_BITS;
/**
* 机器标识最大值 (2^5 / 2 - 1 = 15)
*/
private static final long WORKER_ID_MAX = ((1 << WORKER_ID_BITS) - 1) >> 1;
/**
* 机器标识最大值 (2^5 = 32)
*/
private static final long DATACENTER_ID_MAX = -1L ^ (-1L << DATACENTER_ID_BITS);
/**
* 备份机器ID开始位置 (2^5 / 2 = 16)
*/
private static final long BACK_WORKER_ID_BEGIN = (1 << WORKER_ID_BITS) >> 1;
/**
* 自增序列最大值 (2^11 - 1 = 2047)
*/
private static final long SEQUENCE_MAX = (1 << SEQUENCE_ID_BITS) - 1;
/**
* 发生时间回拨时容忍的最大回拨时间 (秒)
*/
private static final long BACK_TIME_MAX = 1L;
/**
* 上次生成ID的时间戳 (秒)
*/
private static long lastTimestamp = 0L;
/**
* 当前秒内序列 (2^16)
*/
private static long sequence = 0L;
/**
* 备份机器上次生成ID的时间戳 (秒)
*/
private static long lastTimestampBak = 0L;
/**
* 备份机器当前秒内序列 (2^16)
*/
private static long sequenceBak = 0L;
private static long dataCenterId;
private static SequenceUtils idWorker;
static {
dataCenterId = Math.abs(getDataCenterId().hashCode()) % 16;
// dataCenterId = Math.abs(System.getProperty("dataCenterId").hashCode()) % 16;
idWorker = new SequenceUtils(getWorkId(), dataCenterId);
}
/**
* 私有构造函数禁止外部访问
*/
private SequenceUtils() {
}
public SequenceUtils(long workerId, long datacenterId) {
if (workerId > WORKER_ID_MAX || workerId < 0) {
throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0,workerId: %d.", WORKER_ID_MAX, workerId));
}
if (datacenterId > DATACENTER_ID_MAX || datacenterId < 0) {
throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0,datacenterId: %d.", DATACENTER_ID_MAX, datacenterId));
}
this.WORKER_ID = workerId;
this.DATACENTER_ID = datacenterId;
if (log.isInfoEnabled()) {
log.info("initialize workerId:{},dataCenterId:{}", WORKER_ID, DATACENTER_ID);
}
}
/**
* 获取自增序列
*
* @return long
*/
public static long nextId() {
return idWorker.nextId(SystemClock.now() / 1000);
}
/**
* 主机器自增序列
*
* @param timestamp 当前Unix时间戳
* @return long
*/
private static synchronized long nextId(long timestamp) {
// 时钟回拨检查
if (timestamp < lastTimestamp) {
// 发生时钟回拨
log.warn("时钟回拨, 启用备份机器ID: now: [{}] last: [{}]", timestamp, lastTimestamp);
return nextIdBackup(timestamp);
}
// 开始下一秒
if (timestamp != lastTimestamp) {
lastTimestamp = timestamp;
sequence = 0L;
}
if (0L == (++sequence & SEQUENCE_MAX)) {
// 秒内序列用尽
// log.warn("秒内[{}]序列用尽, 启用备份机器ID序列", timestamp);
sequence--;
return nextIdBackup(timestamp);
}
return ((timestamp - OFFSET) << OFFSET_SHIFT_BITS) | (DATACENTER_ID << DATACENTER_SHIFT_BITS) | (WORKER_ID << WORKER_SHIFT_BITS) | sequence;
}
/**
* 备份机器自增序列
*
* @param timestamp timestamp 当前Unix时间戳
* @return long
*/
private static long nextIdBackup(long timestamp) {
if (timestamp < lastTimestampBak) {
if (lastTimestampBak - SystemClock.now() / 1000 <= BACK_TIME_MAX) {
timestamp = lastTimestampBak;
} else {
throw new RuntimeException(String.format("时钟回拨: now: [%d] last: [%d]", timestamp, lastTimestampBak));
}
}
if (timestamp != lastTimestampBak) {
lastTimestampBak = timestamp;
sequenceBak = 0L;
}
if (0L == (++sequenceBak & SEQUENCE_MAX)) {
// 秒内序列用尽
// logger.warn("秒内[{}]序列用尽, 备份机器ID借取下一秒序列", timestamp);
return nextIdBackup(timestamp + 1);
}
return ((timestamp - OFFSET) << OFFSET_SHIFT_BITS) | (DATACENTER_ID << DATACENTER_SHIFT_BITS) | ((WORKER_ID ^ BACK_WORKER_ID_BEGIN) << WORKER_SHIFT_BITS) | sequenceBak;
}
/**
* workId使用IP生成
*
* @return workId
*/
private static Long getWorkId() {
try {
String hostAddress = Inet4Address.getLocalHost().getHostAddress();
int[] ints = StringUtils.toCodePoints(hostAddress);
int sums = 0;
for (int b : ints) {
sums += b;
}
return (long) (sums % 64);
} catch (UnknownHostException e) {
// 如果获取失败,则使用随机数备用
return RandomUtils.nextLong(0, 63);
}
}
/**
* dataCenterId使用hostName生成
*
* @return dataCenterId
*/
private static Long getDataCenterId() {
try {
String hostName = SystemUtils.getHostName();
int[] ints = StringUtils.toCodePoints(hostName);
int sums = 0;
for (int i : ints) {
sums = sums + i;
}
return (long) (sums % 16);
} catch (Exception e) {
// 失败就随机
return RandomUtils.nextLong(0, 15);
}
}
/**
* 获取分布式id
*
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10; i++) {
long id = SequenceUtils.nextId();
System.out.println(id);
}
}
// static {
// // 初始化机器ID
// // 伪代码: 由你的配置文件获取节点ID
// long workerId = SnowflakeIdUtil.getWorkId();
// if (workerId < 0 || workerId > WORKER_ID_MAX) {
// throw new IllegalArgumentException(String.format("Worker Id范围: 0 ~ %d 目前: %d", WORKER_ID_MAX, workerId));
// }
// WORKER_ID = workerId;
// // 初始化机器ID
// // 伪代码: 由你的配置文件获取节点ID
// long datacenterId = SnowflakeIdUtil.getDataCenterId();
// if (datacenterId < 0 || datacenterId > DATACENTER_ID_MAX) {
// throw new IllegalArgumentException(String.format("Datacenter Id范围: 0 ~ %d 目前: %d", DATACENTER_ID_MAX, workerId));
// }
// DATACENTER_ID = datacenterId;
// if (log.isInfoEnabled()){
// log.info("initialize workerId:{},dataCenterId:{}",WORKER_ID,DATACENTER_ID);
// }
// }
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/65731.html