前言

snowflake可以生成全局唯一且有序的Id,相对来说UUID也可以实现,但是无序且长度太长,为36位。

  • 第一位固定为0,表示正数
  • 41位表示时间戳,一共可以使用69年
  • 5位表示数据中心节点,5位表示机器标识,一共可以支持1024个节点
  • 12位表示一毫秒内的序列号,共4096个

代码实现

/** 
 * 分布式Id生成器-雪花算法 
 */ 
public class SnowFlake { 
 
  /** 
   * 起始的时间戳 
   */ 
  private final static long START_STMP = 1480166465631L; 
 
  /** 
   * 每一部分占用的位数 
   */ 
  private final static long SEQUENCE_BIT = 12; //序列号占用的位数 
  private final static long MACHINE_BIT = 5;   //机器标识占用的位数 
  private final static long DATACENTER_BIT = 5;//数据中心占用的位数 
 
  /** 
   * 每一部分的最大值 
   */ 
  private final static long MAX_DATACENTER_NUM = ~(-1L << DATACENTER_BIT); 
  private final static long MAX_MACHINE_NUM = ~(-1L << MACHINE_BIT); 
  private final static long MAX_SEQUENCE = ~(-1L << SEQUENCE_BIT); 
 
  /** 
   * 每一部分向左的位移 
   */ 
  private final static long MACHINE_LEFT = SEQUENCE_BIT; 
  private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT; 
  private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT; 
 
  private long datacenterId;  //数据中心 
  private long machineId;     //机器标识 
  private long sequence = 0L; //序列号 
  private long lastStmp = -1L;//上一次时间戳 
 
  public SnowFlake(long datacenterId, long machineId) { 
    if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) { 
      throw new IllegalArgumentException( 
          "datacenterId can't be greater than MAX_DATACENTER_NUM or less than 0"); 
    } 
    if (machineId > MAX_MACHINE_NUM || machineId < 0) { 
      throw new IllegalArgumentException( 
          "machineId can't be greater than MAX_MACHINE_NUM or less than 0"); 
    } 
    this.datacenterId = datacenterId; 
    this.machineId = machineId; 
  } 
 
  /** 
   * 产生下一个ID 
   */ 
  public synchronized long nextId() { 
    long currStmp = getNewstmp(); 
    if (currStmp < lastStmp) { 
      throw new RuntimeException("Clock moved backwards.  Refusing to generate id"); 
    } 
 
    if (currStmp == lastStmp) { 
      //相同毫秒内,序列号自增 
      sequence = (sequence + 1) & MAX_SEQUENCE; 
      //同一毫秒的序列数已经达到最大4096 
      if (sequence == 0L) { 
        currStmp = getNextMill(); 
      } 
    } else { 
      //不同毫秒内,序列号置为0 
      sequence = 0L; 
    } 
 
    lastStmp = currStmp; 
 
    return (currStmp - START_STMP) << TIMESTMP_LEFT //时间戳部分 
        | datacenterId << DATACENTER_LEFT       //数据中心部分 
        | machineId << MACHINE_LEFT             //机器标识部分 
        | sequence;                             //序列号部分 
  } 
 
  private long getNextMill() { 
    long mill = getNewstmp(); 
    while (mill <= lastStmp) { 
      mill = getNewstmp(); 
    } 
    return mill; 
  } 
 
  private long getNewstmp() { 
    return System.currentTimeMillis(); 
  } 
} 

测试代码

public class Main { 
 
  public static void main(String[] args) { 
    SnowFlake snowFlake = new SnowFlake(0, 0); 
    for (int i = 0; i < 10; i++) { 
      System.out.println(snowFlake.nextId()); 
    } 
  } 
 
} 

输出结果

545435039291146240 
545435039291146241 
545435039291146242 
545435039291146243 
545435039291146244 
545435039291146245 
545435039291146246 
545435039291146247 
545435039291146248 
545435039291146249 

参考

Twitter的分布式自增ID算法snowflake (Java版)
【Java】分布式自增ID算法---雪花算法 (snowflake,Java版)
开源实现


评论关闭
IT序号网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!