SnowFlake雪花算法

需求:分布式环境下,生成唯一自增ID

参考了snowflake算法的生成自增序列方法

/**
 * 线程安全的ID自增工具类,保证同一毫秒内,生成不重复,递增的ID
 *
 * @author Miguel.hou
 * @version v1.0
 * @date 2019-10-17
 */
public class TradeNoGenerateUtils {

    private long sequence; //序列号
    private long lastStamp;//上一次时间戳
    private int maxSequence; //最大的自增位数
    private int maxBit; // 最大位数

    public TradeNoGenerateUtils(int maxBit) {
        this.sequence = 0;
        this.lastStamp = -1L;
        this.maxBit = maxBit;

        if (maxBit <= 0) {
            throw new IllegalArgumentException("maxBit must greater than zero");
        }
        this.maxSequence = (int) Math.pow(10, maxBit);
    }

    /**
     * 不足位补零
     * @return
     */
    private String padding(long id) {
        StringBuilder sb = new StringBuilder();

        int paddingNum = maxBit - String.valueOf(id).length();
        for (int i = 0; i < paddingNum; i++) {
            sb.append("0");
        }
        sb.append(id);
        return sb.toString();
    }

    /**
     * 产生tradeNo
     * 
     * @param methodCode 方法代码
     * @param serverNo 机器号
     * @return
     */
    public synchronized String generateTradeNo(String methodCode, String serverNo) {
        long currStamp = getNewstmp();
        if (currStamp < lastStamp) {
            throw new RuntimeException("Clock moved backwards.  Refusing to generate id");
        }

        if (currStamp == lastStamp) {
            //相同毫秒内,序列号自增
            sequence = (sequence + 1) % maxSequence;
            //同一毫秒的序列数已经达到最大
            if (sequence == 0L) {
                currStamp = getNextMill();
            }
        } else {
            //不同毫秒内,序列号置为0
            sequence = 0L;
        }

        lastStamp = currStamp;

        String no = methodCode + DateUtil.parseTimeStamp(currStamp) + padding(sequence) + serverNo;
        return no + GeneralUtil.getLUHNCode(no);

    }

    private long getNextMill() {
        long mill = getNewstmp();
        while (mill <= lastStamp) {
            mill = getNewstmp();
        }
        return mill;
    }

    private long getNewstmp() {
        return System.currentTimeMillis();
    }

    public static void main(String[] args) {
        TradeNoGenerateUtils autoIncrIdUtils = new TradeNoGenerateUtils(3);
        for (int i = 0; i < (1 << 12); i++) {
            System.out.println(autoIncrIdUtils.generateTradeNo("1000", "0"));
        }
    }
}