雪花算法

囧囧 1年前 ⋅ 3991 阅读

雪花算法生产的Id 的结果是一个64bit大小的整数

  • 1位 ,不用。二进制中最高位为1的都是附属,但是我们生产的id一般都是使用整数,所以这个最高位固定是0
  • 41位,用来记录时间戳
  • 10位,用来记录工作机器ID
  • 12位,序列号,用来记录同好卖哦内生产的不同ID

雪花优势:

  • 1.所有生成的id按时间递增
  • 2.整个分布式系统内不会生产重复ID

JAVA代码实现

/**
 * @Description 雪花主键ID生成
 * @Author qi
 **/
public class SnowflakeIdGenerate implements IdGenerate<Long> {

    /**
     * 开始时间戳
     */
    private final long twepoch = 1420041600000L;

    /**
     * 机器id所占的位数
     */
    private final long workerIdBits = 5L;

    /**
     * 数据标识id所占的位数
     */
    private final long dataCenterIdBits = 5L;

    /**
     * 支持的最大机器ID,结果是31(位移算法可以很快计算出二进制所能表示的最大十进制数)
     */
    private final long maxWorkerId = -1L^(-1L<<workerIdBits);

    /**
     * 支持的最大数据标识DI,结果是31
     */
    private final long maxDataCenterId = -1L^(-1L<<dataCenterIdBits);

    /**
     * 序列在id中咱的位数
     */
    private final long sequenceBits = 12L;

    /**
     * 机器ID向左位移12位
     */
    private final long workerIdShift = sequenceBits;

    /**
     * 数据标识ID向左位移17位(12+5)
     */
    private final long dataCenterIdShift = sequenceBits+workerIdBits;

    /**
     * 时间戳向左位移22位(12+5+5)
     */
    private final long timestampLeftShift =sequenceBits+workerIdBits+dataCenterIdShift;

    /**
     * 生成序列的掩码,这里为4095
     */
    private final long sequenceMask = -1L^(-1L<<sequenceBits);

    /**
     * 工作机器ID(0-31)
     */
    private long workerId;
    /**
     * 数据中心ID(0-31)
     */
    private long dataCenterId;
    /**
     * 毫秒内序列(0-4095)
     */
    private long sequence = 0L;
    /**
     * 上次生成ID的时间戳
     */
    private long lastTimeStamp = -1L;

    /**
     * 构造方法
     * @param workerId 机器ID
     * @param dataCenterId 数据中心ID
     */
    public SnowflakeIdGenerate(long workerId, long dataCenterId) {
        if (workerId>maxWorkerId||workerId<0){
            throw new IllegalArgumentException();
        }
        if (dataCenterId>maxDataCenterId||dataCenterId<0){
            throw new IllegalArgumentException();
        }
        this.workerId = workerId;
        this.dataCenterId = dataCenterId;
    }

    @Override
    public synchronized Long nextId() {

        long timestamp = timeGen();
        if (timestamp<lastTimeStamp){
            throw new RuntimeException(
                    String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimeStamp - timestamp));
        }
        if (lastTimeStamp == timestamp){
            sequence = (sequence+1)&sequenceMask;
            if (sequenceMask == 0){
                timestamp = tilNextMillis(lastTimeStamp);
            }
        }else {
            sequence = 0L;
        }
        //上次生成ID的时间戳
        lastTimeStamp = timestamp;
        return ((timestamp-twepoch)<<timestampLeftShift)
                |(dataCenterId<<dataCenterIdShift)
                |(workerId<<workerIdShift)
                |sequence;
    }

    /**
     * 阻塞到下一个毫秒,知道获取新的时间戳
     * @param lastTimestamp
     * @return
     */
    private long tilNextMillis(long lastTimestamp){
        long timestamp = timeGen();
        while (timestamp<=lastTimestamp){
            timestamp = timeGen();
        }
        return timestamp;
    }

    /**
     * 获取当前时间戳
     * @return
     */
    private long timeGen(){

        return System.currentTimeMillis();
    }

}

全部评论: 0

    我有话说: