zoukankan      html  css  js  c++  java
  • IdGenerator(雪花)

    /**
    * tweeter的snowflake 移植到Java.参考资料:https://github.com/twitter/snowflake
    * id构成: 42位的时间前缀 + 10位的节点标识 + 12位的sequence避免并发的数字(12位不够用时强制得到新的时间前缀)
    * id单调递增,长整型
    * 注意这里进行了小改动: snowkflake是5位的datacenter加5位的机器id; 这里变成使用10位的机器id
    * snowkflake当时间调整时将拒绝分配ID,这里改成分配UUID的tMostSignificantBits
    * 通过取服务器名中的编号来分配机器id,实现了去中心化【仅适用于包含编号的机器】
    * 使用:long id = IdGenerator.nextId();
    */
    @Log4j2
    public final class IdGenerator {
    /**
    * 每台机器分配不同的id
    */
    private static final long WORKER_ID;

    /**
    * 时间起始标记点,作为基准,一般取系统的最近时间
    */
    private static final long EPOCH_NUM = 1568017964000L;

    /**
    * 机器标识位数
    */
    private static final long WORKER_IDBITS = 10L;

    /**
    * 机器ID最大值: 1023
    */
    private static final long MAXWORKER_ID = -1L ^ -1L << WORKER_IDBITS;

    /**
    * 毫秒内自增位
    */
    private static final long SEQUENCE_BITS = 12L;

    /**
    * 12
    */
    private static final long WORKER_IDSHIFT = SEQUENCE_BITS;

    /**
    * 22
    */
    private static final long TIMESTAMP_LEFTSHIFT = WORKER_IDBITS + SEQUENCE_BITS;

    /**
    * 4095,111111111111,12位
    */
    private static final long SEQUENCE_MASK = -1L ^ -1L << SEQUENCE_BITS;

    /**
    * 0,并发控制
    */
    private static long sequenceSe = 0L;

    private static long lastTimestamp = -1L;

    static {
    String hostName = null;
    try {
    InetAddress netAddress = InetAddress.getLocalHost();
    hostName = netAddress.getHostName();
    } catch (UnknownHostException e) {
    log.error(e);
    }
    if (null != hostName && !"".equals(hostName)) {
    String hostNo = "";
    for (int i = 0; i < hostName.length(); i++) {
    if (hostName.charAt(i) > 48 && hostName.charAt(i) <= 57) {
    // 取最后一组数字
    if ("".equals(hostNo)) {
    hostNo += hostName.charAt(i);
    } else {
    hostNo = "";
    hostNo += hostName.charAt(i);
    }
    }
    }
    if (!"".equals(hostNo)) {
    WORKER_ID = Integer.parseInt(hostNo) % MAXWORKER_ID;
    } else {
    WORKER_ID = new SecureRandom().nextInt(1000) + 1;
    }

    } else {
    WORKER_ID = new SecureRandom().nextInt(1000) + 1;
    }
    }

    /**
    * Next id long.
    *
    * @return the long
    */
    public static synchronized long nextId() {
    long timestamp = timeGen();
    // 如果上一个timestamp与新产生的相等,则sequence加一(0-4095循环); 对新的timestamp,sequence从0开始
    if (lastTimestamp == timestamp) {
    sequenceSe = sequenceSe + 1 & SEQUENCE_MASK;
    if (sequenceSe == 0) {
    // 重新生成timestamp
    timestamp = tilNextMillis(lastTimestamp);
    }
    } else {
    sequenceSe = 0;
    }

    if (timestamp < lastTimestamp) {
    UUID uuid = UUID.randomUUID();
    return uuid.getMostSignificantBits();
    }

    lastTimestamp = timestamp;
    return timestamp - EPOCH_NUM << TIMESTAMP_LEFTSHIFT | WORKER_ID << WORKER_IDSHIFT | sequenceSe;
    }

    /**
    *
    */
    /**
    * 等待下一个毫秒的到来, 保证返回的毫秒数在参数lastTimestamp之后
    *
    * @param lastTimestamp the last Timestamp
    * @return the long
    */
    private static long tilNextMillis(long lastTimestamp) {
    long timestamp = timeGen();
    while (timestamp <= lastTimestamp) {
    timestamp = timeGen();
    }
    return timestamp;
    }

    /**
    * 获得系统当前毫秒数
    *
    * @return the long
    */
    public static long timeGen() {
    return System.currentTimeMillis();
    }

    }
  • 相关阅读:
    27. Remove Element
    列表变成字典
    1. Two Sum
    CVPR2019:What and How Well You Performed? A Multitask Learning Approach to Action Quality Assessment
    959. Regions Cut By Slashes
    118. Pascal's Triangle
    loj3117 IOI2017 接线 wiring 题解
    题解 NOI2019 序列
    题解 省选联考2020 组合数问题
    题解 Educational Codeforces Round 90 (Rated for Div. 2) (CF1373)
  • 原文地址:https://www.cnblogs.com/lhh-boke/p/15064931.html
Copyright © 2011-2022 走看看