ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

java雪花算法

2022-01-23 13:57:59  阅读:182  来源: 互联网

标签:java timestamp 雪花 long lastTimestamp 算法 static private id


使用场景 : 雪花算法能生成唯一18位id , 适用于生成订单id等 , 优点普通自增id , 可能通过id计算出当天或本月的销量 , 雪花算法可以避免这个问题

java代码实现

class SnowFlake {


// ==============================Fields===========================================
/** 开始时间截 (2015-01-01) */
private static final long twepoch = 1420041600000L;

/** 机器id所占的位数 */
private static final long workerIdBits = 5L;

/** 数据标识id所占的位数 */
private static final long datacenterIdBits = 5L;

/** 支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) */
private static final long maxWorkerId = -1L ^ (-1L << workerIdBits);

/** 支持的最大数据标识id,结果是31 */
private static final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);

/** 序列在id中占的位数 */
private static final long sequenceBits = 12L;

/** 机器ID向左移12位 */
private static final long workerIdShift = sequenceBits;

/** 数据标识id向左移17位(12+5) */
private static final long datacenterIdShift = sequenceBits + workerIdBits;

/** 时间截向左移22位(5+5+12) */
private static final long timestampLeftShift = sequenceBits + workerIdBits
        + datacenterIdBits;

/** 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095) */
private  static final long sequenceMask = -1L ^ (-1L << sequenceBits);

/** 工作机器ID(0~31) */
private static long workerId;

/** 数据中心ID(0~31) */
private static long datacenterId;

/** 毫秒内序列(0~4095) */
private static long sequence = 0L;

/** 上次生成ID的时间截 */
private static long lastTimestamp = -1L;

// ==============================Constructors=====================================
/**
 * 构造函数
 *
 * @param workerId
 *            工作ID (0~31)
 * @param datacenterId
 *            数据中心ID (0~31)
 */
public SnowFlake(long workerId, long datacenterId) {
    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));
    }
    SnowFlake.workerId = workerId;
    SnowFlake.datacenterId = datacenterId;
}

// ==============================Methods==========================================
/**
 * 获得下一个ID (该方法是线程安全的)
 *
 * @return SnowflakeId
 */
public static 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 static long tilNextMillis(long lastTimestamp) {
    long timestamp = timeGen();
    while (timestamp <= lastTimestamp) {
        timestamp = timeGen();
    }
    return timestamp;
}

/**
 * 返回以毫秒为单位的当前时间
 *
 * @return 当前时间(毫秒)
 */
protected static long timeGen() {
    return System.currentTimeMillis();
}

public SnowFlake() {
    this(0, 0);
}

// 生成id
public static String getId() {
    return String.valueOf(SnowFlake.nextId());
}

// ==============================Test=============================================
/** 测试 */
public static void main(String[] args) {
    System.out.println(SnowFlake.nextId());
}

}

此段代码出处不详 , 如有侵权 , 请联系作者!

标签:java,timestamp,雪花,long,lastTimestamp,算法,static,private,id
来源: https://blog.csdn.net/LongoingCHU/article/details/122650709

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有