博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
雪花算法
阅读量:6249 次
发布时间:2019-06-22

本文共 4746 字,大约阅读时间需要 15 分钟。

hot3.png

import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Calendar;import java.util.Date;import lombok.Data;import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Service;/** * Twitter_Snowflake SnowFlake的结构如下(每部分用-分开): 0 - 0000000000 0000000000 0000000000 0000000000 0 - * 00000 - 00000 - 000000000000 1位标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0 * 41位时间截(毫秒级),注意,41位时间截不是存储当前时间的时间截,而是存储时间截的差值(当前时间截 - 开始时间截) 得到的值),这里的的开始时间截, * 一般是我们的id生成器开始使用的时间,由我们程序来指定的(如下下面程序IdWorker类的startTime属性)。41位的时间截,可以使用69年,年T = (1L << 41) / * (1000L * 60 * 60 * 24 * 365) = 69 10位的数据机器位,可以部署在1024个节点,包括5位datacenterId和5位workerId * 12位序列,毫秒内的计数,12位的计数顺序号支持每个节点每毫秒(同一机器,同一时间截)产生4096个ID序号 加起来刚好64位,为一个Long型。 * SnowFlake的优点是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分),并且效率较高,经测试, * SnowFlake每秒能够产生26万ID左右。 * * @author vendor * @date 2017-10-19 */@Servicepublic class Snowflake {  // ==============================Fields===========================================  /**   * 开始时间截 (2017-01-01)   */  private final long twepoch = 1483200060000L;  /**   * 机器id所占的位数   */  private final long workerIdBits = 5L;  /**   * 数据标识id所占的位数   */  private final long datacenterIdBits = 5L;  /**   * 支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数)   */  private final long maxWorkerId = -1L ^ (-1L << workerIdBits);  /**   * 支持的最大数据标识id,结果是31   */  private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);  /**   * 序列在id中占的位数   */  private final long sequenceBits = 12L;  /**   * 机器ID向左移12位   */  private final long workerIdShift = sequenceBits;  /**   * 数据标识id向左移17位(12+5)   */  private final long datacenterIdShift = sequenceBits + workerIdBits;  /**   * 时间截向左移22位(5+5+12)   */  private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;  /**   * 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095)   */  private final long sequenceMask = -1L ^ (-1L << sequenceBits);  /**   * 工作机器ID(0~31)   */  @Value("${snowflake.worker}")  private long workerId;  /**   * 数据中心ID(0~31)   */  @Value("${snowflake.datacenter}")  private long datacenterId;  /**   * 毫秒内序列(0~4095)   */  private long sequence = 0L;  /**   * 上次生成ID的时间截   */  private long lastTimestamp = -1L;  //==============================Constructors=====================================  /**   * 构造函数   *   * @param workerId 工作ID (0~31)   * @param datacenterId 数据中心ID (0~31)   */  public Snowflake() {    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));    }  }  // ==============================Methods==========================================  /**   * 获得下一个ID (该方法是线程安全的)   *   * @return SnowflakeId   */  public synchronized long nextId() {    long timestamp = timeGen();    //如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常    if (timestamp < lastTimestamp) {      throw new RuntimeException(          String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds",              lastTimestamp - timestamp));    }    //如果是同一时间生成的,则进行毫秒内序列    if (lastTimestamp == timestamp) {      sequence = (sequence + 1) & sequenceMask;      //毫秒内序列溢出      if (sequence == 0) {        //阻塞到下一个毫秒,获得新的时间戳        timestamp = tilNextMillis(lastTimestamp);      }    }    //时间戳改变,毫秒内序列重置    else {      sequence = 0L;    }    //上次生成ID的时间截    lastTimestamp = timestamp;    //移位并通过或运算拼到一起组成64位的ID    return ((timestamp - twepoch) << timestampLeftShift)        | (datacenterId << datacenterIdShift)        | (workerId << workerIdShift)        | sequence;  }  /**   * 阻塞到下一个毫秒,直到获得新的时间戳   *   * @param lastTimestamp 上次生成ID的时间截   * @return 当前时间戳   */  protected long tilNextMillis(long lastTimestamp) {    long timestamp = timeGen();    while (timestamp <= lastTimestamp) {      timestamp = timeGen();    }    return timestamp;  }  /**   * 返回以毫秒为单位的当前时间   *   * @return 当前时间(毫秒)   */  protected long timeGen() {    return System.currentTimeMillis();  }  //==============================Test=============================================  /**   * 测试   *///  public static void main(String[] args) {//    Snowflake idWorker = new Snowflake(0, 0);//    System.out.println(idWorker.nextId());////    SimpleDateFormat format = new SimpleDateFormat("yyyy-mm-dd");//    try {//      Date date = format.parse("2017-01-01");//      System.out.println(date.getTime());//    } catch (ParseException e) {//      e.printStackTrace();//    }//  }}

 

转载于:https://my.oschina.net/u/818848/blog/1790442

你可能感兴趣的文章
【leetcode】124. Binary Tree Maximum Path Sum
查看>>
Flex实现 WebQQ那白云草地主题,云朵飘!
查看>>
安装meteor运行基本demo发生错误。
查看>>
Hibernate之QBC .HQL 查询
查看>>
当程序执行时间很快,控制台没显示执行代码和数据库
查看>>
为什么一般的性能测试要在局域进行?
查看>>
Linux 系统目录;
查看>>
[Android Studio 权威教程]断点调试和高级调试
查看>>
阶乘求和之最后一位
查看>>
Eclipse 乱码解决方案(UTF8 -- GBK)
查看>>
网络编程
查看>>
Debian安装Chrome
查看>>
民生银行十五年的数据体系建设,深入解读阿拉丁大数据生态圈、人人BI 是如何养成的?【转】...
查看>>
使用别的电脑连接另一台电脑当中的虚拟机中的kylin项目
查看>>
空间统计笔记之二(分布模式工具集,Analyzing Patterns Toolset)
查看>>
一定要为了成功才去创业吗?
查看>>
4.2 列表生成式、迭代器与生成器
查看>>
Sql Server系列:分区表操作
查看>>
myeclipse maven tomcat插件 创建web工程
查看>>
2.java线程之ThreadLocal
查看>>