雪花(SnowFlake)算法学习

上代码

class CustomSnowFlake {
  /**
   * 开始时间
   */
  private static final long startTimestamp = 1561077901000L;

  /** 最后一次时间戳 */
  private static long lastTimestamp = -1L;

  // 序列号
  private static long sequence = 0L;
  private static final long sequenceBits = 12;
  private static final long maxSequence = ~(-1L << sequenceBits);
  /** 工作线程 */
  private static final long workerIdBits = 5;
  private static final long workerIdShift = sequenceBits;
  private static final long maxWorkerId = ~(-1L << workerIdBits);
  /** 数据中心 */
  private static final long dataCenterIdBits = 5;
  private static final long dataCenterIdShift = workerIdShift + workerIdBits;
  private static final long maxDataCenterId = ~(-1L << dataCenterIdBits);
  /** 时间戳 */
  private static final long timestampShift = dataCenterIdShift + dataCenterIdBits;

  private long dataCenterId;
  private long workerId;


  public CustomSnowFlake(long dataCenterId, long workerId) {
    if (dataCenterId > maxDataCenterId || dataCenterId < 0) {
      throw new IllegalArgumentException("数据中心id需要在0-31之间!");
    }

    if (workerId > maxWorkerId || workerId < 0) {
      throw new IllegalArgumentException("工作id需要在0-31之间!");
    }
    this.dataCenterId = dataCenterId;
    this.workerId = workerId;
  }

  public synchronized long nextId() {
    // 查看时间是否回流
    long timestamp = getTimestamp();
    if (timestamp < lastTimestamp) {
      throw new RuntimeException("时间回调,拒绝生成id");
    }

    // 查看时间是否在同一毫秒内
    if (timestamp == lastTimestamp) {
      sequence = (sequence + 1) & maxSequence;
      if (sequence == 0) {
        timestamp = getNextMill();
        sequence = 0;
      }
    } else {
      sequence = 0;
    }

    lastTimestamp = timestamp;

    return (timestamp - startTimestamp) << timestampShift
            | dataCenterId << dataCenterIdShift
            | workerId << workerIdShift
            | sequence;
  }

  /**
   * 获取下一毫秒
   *
   * @return 时间戳
   */
  private long getNextMill() {
    long timestamp = getTimestamp();
    while (timestamp <= lastTimestamp) {
      timestamp = getTimestamp();
    }
    return timestamp;
  }

  /**
   * 时间戳
   *
   * @return 当前时间的时间戳
   */
  private long getTimestamp() {
    return System.currentTimeMillis();
  }
}

测试

class Main {
  public static void main(String[] args) {
    m2();
  }

  private static void m2() {
    final Set<Long> ids = new HashSet<>();
    final CustomSnowFlake customSnowFlake = new CustomSnowFlake(1, 1);
    int num = 10000;
    for (int i = 0; i < num; i++) {
      final long id = customSnowFlake.nextId();
      ids.add(id);
      System.out.println(System.currentTimeMillis()+"=="+id);
    }

    System.out.println(num == ids.size());
  }
}

结果

问题

1、为啥用-1L进行位移,不用1L呢;(自己测试一下,便知其中奥妙!

2、~(...) 这个符号的作用!(忍不住想说一下:跟 -1L^(...) 等价

3、为啥 (sequence + 1) & sequenceMask; 有等于0的情况!(提示:位不够了,jvm默认不报错

结论

1、约300个/毫秒

2、有14个字符,最多有19个,69年一轮回(画外音:我感觉应该弄成60,一个甲子吗);

3、按一个long类型长度(64位)计算;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值