All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.guerlab.spring.commons.sequence.Sequence Maven / Gradle / Ivy

package net.guerlab.spring.commons.sequence;

/**
 * @author guer
 *
 */
public class Sequence {

    /** 起始时间戳,用于用当前时间戳减去这个时间戳,算出偏移量 **/
    private final long startTime = 1519740777809L;

    /** workerId占用的位数5(表示只允许workId的范围为:0-1023) **/
    private final long workerIdBits = 5L;

    /** dataCenterId占用的位数:5 **/
    private final long dataCenterIdBits = 5L;

    /** 序列号占用的位数:12(表示只允许workId的范围为:0-4095) **/
    private final long sequenceBits = 12L;

    /** workerId可以使用的最大数值:31 **/
    private final long maxWorkerId = -1L ^ -1L << workerIdBits;

    /** dataCenterId可以使用的最大数值:31 **/
    private final long maxDataCenterId = -1L ^ -1L << dataCenterIdBits;

    private final long workerIdShift = sequenceBits;

    private final long dataCenterIdShift = sequenceBits + workerIdBits;

    private final long timestampLeftShift = sequenceBits + workerIdBits + dataCenterIdBits;

    /** 用mask防止溢出:位与运算保证计算的结果范围始终是 0-4095 **/
    private final long sequenceMask = -1L ^ -1L << sequenceBits;

    private long workerId;

    private long dataCenterId;

    private long sequence = 0L;

    private long lastTimestamp = -1L;

    private boolean isClock = false;

    /**
     * 基于Snowflake创建分布式ID生成器
     * 

* 注:sequence * * @param workerId * 工作机器ID,数据范围为0~31 * @param dataCenterId * 数据中心ID,数据范围为0~31 */ public Sequence(long workerId, long dataCenterId) { 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)); } this.workerId = workerId; this.dataCenterId = dataCenterId; } public void setClock( boolean clock) { isClock = clock; } /** * 获取ID * * @return ID */ public synchronized Long nextId() { long timestamp = timeGen(); // 闰秒:如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常 if (timestamp < lastTimestamp) { long offset = lastTimestamp - timestamp; if (offset <= 5) { try { this.wait(offset << 1); timestamp = timeGen(); if (timestamp < lastTimestamp) { throw new RuntimeException(String .format("Clock moved backwards. Refusing to generate id for %d milliseconds", offset)); } } catch (Exception e) { throw new RuntimeException(e); } } else { throw new RuntimeException( String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", offset)); } } // 解决跨毫秒生成ID序列号始终为偶数的缺陷:如果是同一时间生成的,则进行毫秒内序列 if (lastTimestamp == timestamp) { // 通过位与运算保证计算的结果范围始终是 0-4095 sequence = sequence + 1 & sequenceMask; if (sequence == 0) { timestamp = tilNextMillis(lastTimestamp); } } else { // 时间戳改变,毫秒内序列重置 sequence = 0L; } lastTimestamp = timestamp; /* * 1.左移运算是为了将数值移动到对应的段(41、5、5,12那段因为本来就在最右,因此不用左移) * 2.然后对每个左移后的值(la、lb、lc、sequence)做位或运算,是为了把各个短的数据合并起来,合并成一个二进制数 * 3.最后转换成10进制,就是最终生成的id */ return timestamp - startTime << timestampLeftShift | dataCenterId << dataCenterIdShift | workerId << workerIdShift | sequence; } /** * 保证返回的毫秒数在参数之后(阻塞到下一个毫秒,直到获得新的时间戳) * * @param lastTimestamp * lastTimestamp * @return timestamp */ private long tilNextMillis( long lastTimestamp) { long timestamp = timeGen(); while (timestamp <= lastTimestamp) { timestamp = timeGen(); } return timestamp; } /** * 获得系统当前毫秒数 * * @return timestamp */ private long timeGen() { if (isClock) { // 解决高并发下获取时间戳的性能问题 return SystemClock.now(); } else { return System.currentTimeMillis(); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy