雪花算法组成
10bit工作进程位:用来记录工作机器的id,包括5位datacenterId和5位workerId;5位(bit)可以表示的最大正整数是31,即可以用0,1,2,3,…31这32个数字,来表示不同的datacenterId和workerId
Hutool工具包
cn.hutool hutool-all 5.7.16
Snowflake需自行保证单例,否则多个对象生成ID会导致重复
代码
package com.lyods.base.utils;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.net.NetUtil;
import cn.hutool.core.util.IdUtil;
import javax.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SnowFlakeUtil {
private final static Logger log = LoggerFactory.getLogger(SnowFlakeUtil.class);
private static long workerId = 0;
private volatile static Snowflake snowflake = null;
private volatile static SnowFlakeUtil sfu = null;
private SnowFlakeUtil() {
}
public static SnowFlakeUtil getInstance() {
if (null == sfu) {
synchronized (SnowFlakeUtil.class) {
if (null == sfu) {
sfu = new SnowFlakeUtil();
}
}
}
return sfu;
}
public long snowflakeId() {
if (null == snowflake) {
snowflake = getSnowflake();
}
return snowflake.nextId();
}
public long snowflakeId(long workerId, long dataCenterId) {
if (null == snowflake) {
snowflake = getSnowflake(workerId, dataCenterId);
}
return snowflake.nextId();
}
private synchronized Snowflake getSnowflake(long workerId, long dataCenterId) {
snowflake = IdUtil.getSnowflake(workerId, dataCenterId);
return snowflake;
}
private synchronized Snowflake getSnowflake() {
snowflake = new Snowflake();
return snowflake;
}
@PostConstruct
public void init() {
try {
workerId = NetUtil.ipv4ToLong(NetUtil.getLocalhostStr());
log.info("当前机器的workId: {}", workerId);
} catch (Exception e) {
e.printStackTrace();
log.error("当前机器的workId获取失败", e);
workerId = NetUtil.getLocalhostStr().hashCode();
}
}
}
线程池30线程测试
ExecutorService executorService = Executors.newFixedThreadPool(5);
Stream.iterate(0, x -> x + 1).limit(30).forEach(x -> {
executorService.submit(() -> {
long id = SnowFlakeUtil.getInstance().snowflakeId();
System.out.println(id);
});
});
结果
- 优点
时间戳位在高位,ID趋势递增(几千页的分页下可以根据最后一条数据ID进行分页提高效率),生成ID性能高,不依赖第三方系统,分布式系统内不会产生ID碰撞(由datacenter和workerId作区分) - 缺点
回拨本机时间可能导致时间戳相同,ID重复,分布式下不同机器可能时间不完全同步



