雪花算法生成id

public class IdWorker{

//下面两个每个5位,加起来就是10位的工作机器id
private long workerId;    //工作id
private long datacenterId;   //数据id
//12位的序列号
private long sequence;

public IdWorker(long workerId, long datacenterId, long sequence){
    // sanity check for workerId
    if (workerId > maxWorkerId || workerId < 0) {
        throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0",maxWorkerId));
    }
    if (datacenterId > maxDatacenterId || datacenterId < 0) {
        throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0",maxDatacenterId));
    }
    System.out.printf("worker starting. timestamp left shift %d, datacenter id bits %d, worker id bits %d, sequence bits %d, workerid %d",
            timestampLeftShift, datacenterIdBits, workerIdBits, sequenceBits, workerId);

    this.workerId = workerId;
    this.datacenterId = datacenterId;
    this.sequence = sequence;
}

//初始时间戳
private long twepoch = 1288834974657L;

//长度为5位
private long workerIdBits = 5L;
private long datacenterIdBits = 5L;
//最大值
private long maxWorkerId = -1L ^ (-1L << workerIdBits);
private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
//序列号id长度
private long sequenceBits = 12L;
//序列号最大值
private long sequenceMask = -1L ^ (-1L << sequenceBits);

//工作id需要左移的位数,12位
private long workerIdShift = sequenceBits;
//数据id需要左移位数 12+5=17位
private long datacenterIdShift = sequenceBits + workerIdBits;
//时间戳需要左移位数 12+5+5=22位
private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;

//上次时间戳,初始值为负数
private long lastTimestamp = -1L;

public long getWorkerId(){
    return workerId;
}

public long getDatacenterId(){
    return datacenterId;
}

public long getTimestamp(){
    return System.currentTimeMillis();
}

//下一个ID生成算法
public synchronized long nextId() {
    long timestamp = timeGen();

    //获取当前时间戳如果小于上次时间戳,则表示时间戳获取出现异常
    if (timestamp < lastTimestamp) {
        System.err.printf("clock is moving backwards.  Rejecting requests until %d.", lastTimestamp);
        throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds",
                lastTimestamp - timestamp));
    }

    //获取当前时间戳如果等于上次时间戳(同一毫秒内),则在序列号加一;否则序列号赋值为0,从0开始。
    if (lastTimestamp == timestamp) {
        sequence = (sequence + 1) & sequenceMask;
        if (sequence == 0) {
            timestamp = tilNextMillis(lastTimestamp);
        }
    } else {
        sequence = 0;
    }

    //将上次时间戳值刷新
    lastTimestamp = timestamp;

    /**
     * 返回结果:
     * (timestamp - twepoch) << timestampLeftShift) 表示将时间戳减去初始时间戳,再左移相应位数
     * (datacenterId << datacenterIdShift) 表示将数据id左移相应位数
     * (workerId << workerIdShift) 表示将工作id左移相应位数
     * | 是按位或运算符,例如:x | y,只有当x,y都为0的时候结果才为0,其它情况结果都为1。
     * 因为个部分只有相应位上的值有意义,其它位上都是0,所以将各部分的值进行 | 运算就能得到最终拼接好的id
     */
    return ((timestamp - twepoch) << timestampLeftShift) |
            (datacenterId << datacenterIdShift) |
            (workerId << workerIdShift) |
            sequence;
}

//获取时间戳,并与上次时间戳比较
private long tilNextMillis(long lastTimestamp) {
    long timestamp = timeGen();
    while (timestamp <= lastTimestamp) {
        timestamp = timeGen();
    }
    return timestamp;
}

//获取系统时间戳
private long timeGen(){
    return System.currentTimeMillis();
}

}

1.以上为源码,可作为工具类引用

2.进行测试:

//---------------测试---------------
public static void main(String[] args) {
    IdWorker worker = new IdWorker(1,1,1);
    for (int i = 0; i < 30; i++) {
        System.out.println(worker.nextId());
    }
}

结果:

1417803203289944065
1417803203289944066
1417803203289944067
1417803203289944068
1417803203289944069
1417803203289944070
1417803203289944071
1417803203289944072
1417803203289944073
1417803203289944074
1417803203289944075
1417803203289944076
1417803203289944077
1417803203289944078
1417803203289944079
1417803203289944080
1417803203289944081
1417803203289944082
1417803203289944083
1417803203289944084
1417803203289944085
1417803203289944086
1417803203289944087
1417803203289944088
1417803203289944089
1417803203289944090
1417803203289944091
1417803203289944092
1417803203289944093

发表评论

邮箱地址不会被公开。 必填项已用*标注