代码不多,也容易看懂,就不写注释了。我用此生成订单ID,还比较好用。当然。运用到实际项目中时,最好注册在zookeeper上,获取不同的workId,也可以写在配置文件中,发布的时候改配置文件
/** * 基于Twitter的ID生成器,必须要关闭时间同步 * snowflake的优势 (个人感觉) * 集群环境下,也不会重复(因为有数据中心和机器号) * 每毫秒能产生4000个不重复的号 * 比UUID速度快,Long比varchar速度快的多的多 * 比UUID有顺序。是按照时间顺序来的。 * 标志位-----时间戳----数据中心----机器号----序列 * 目前是发布的时候,写在配置文件里,最好用zookeeper进行选举。 * 代码很简单,就不写注释了 * @Date 2016-12-02 */ public class SnowFlakeId { private long workerId; private long datacenterId; private long sequence = 0L; private long twepoch = 1288834974657L; private long workerIdBits = 5L; private long datacenterIdBits = 5L; private long maxWorkerId = -1L ^ (-1L << workerIdBits); private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits); private long sequenceBits = 12L; private long workerIdShift = sequenceBits; private long datacenterIdShift = sequenceBits + workerIdBits; private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits; private long sequenceMask = -1L ^ (-1L << sequenceBits); private long lastTimestamp = -1L; public SnowFlakeId(long workerId, long datacenterId) { // 检查WorkId if (workerId > maxWorkerId || workerId < 0) { throw new IllegalArgumentException(String.format("节点ID必须在 0 和 %d 之间", maxWorkerId)); } if (datacenterId > maxDatacenterId || datacenterId < 0) { throw new IllegalArgumentException(String.format("数据中心ID必须在 0 和 %d 之间 ", maxDatacenterId)); } this.workerId = workerId; this.datacenterId = datacenterId; } public synchronized long nextId() { long timestamp = System.currentTimeMillis(); if (timestamp < lastTimestamp) { throw new RuntimeException(String.format("时钟竟然倒退了,如何生成ID。老大你在逗我玩吗?拒绝为 %d 秒生成ID", lastTimestamp - timestamp)); } if (lastTimestamp == timestamp) { sequence = (sequence + 1) & sequenceMask; if (sequence == 0) { timestamp = tilNextMillis(lastTimestamp); } } else { sequence = 0L; } lastTimestamp = timestamp; return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence; } protected long tilNextMillis(long lastTimestamp) { long timestamp = System.currentTimeMillis(); while (timestamp <= lastTimestamp) { timestamp = System.currentTimeMillis(); } return timestamp; } }