帮我用java写一个10位的雪花算法
时间: 2023-06-08 14:04:51 浏览: 166
Java实现雪花算法(snowflake)
OK,我可以帮你使用 Java 编写一个 10 位的雪花算法。以下是代码:
```
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
public class Snowflake {
// 开始时间戳(2021-01-01 00:00:00)
private static final long START_TIME = 1609430400000L;
// 机器 ID 占用的位数
private static final long WORKER_ID_BITS = 5L;
// 数据标识 ID 占用的位数
private static final long DATA_CENTER_ID_BITS = 5L;
// 序列号占用的位数
private static final long SEQUENCE_BITS = 12L;
// 支持的最大机器 ID,结果是31
private static final long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS);
// 支持的最大数据标识 ID,结果是31
private static final long MAX_DATA_CENTER_ID = ~(-1L << DATA_CENTER_ID_BITS);
// 机器 ID 左移的位数,结果是12
private static final long WORKER_ID_SHIFT = SEQUENCE_BITS;
// 数据标识 ID 左移的位数,结果是17
private static final long DATA_CENTER_ID_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS;
// 时间戳左移的位数,结果是22
private static final long TIMESTAMP_LEFT_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS + DATA_CENTER_ID_BITS;
// 支持的最大序列号,结果是4095
private static final long MAX_SEQUENCE = ~(-1L << SEQUENCE_BITS);
// 机器 ID
private long workerId;
// 数据标识 ID
private long dataCenterId;
// 序列号
private volatile long sequence = 0L;
// 上次生成 ID 的时间戳
private volatile long lastTimestamp = -1L;
public Snowflake(long workerId, long dataCenterId) {
if (workerId > MAX_WORKER_ID || workerId < 0) {
throw new IllegalArgumentException("workerId can't be greater than " + MAX_WORKER_ID + " or less than 0");
}
if (dataCenterId > MAX_DATA_CENTER_ID || dataCenterId < 0) {
throw new IllegalArgumentException("dataCenterId can't be greater than " + MAX_DATA_CENTER_ID + " or less than 0");
}
this.workerId = workerId;
this.dataCenterId = dataCenterId;
}
/**
* 生成下一个唯一 ID
*
* @return long
*/
public synchronized long nextId() {
long timestamp = System.currentTimeMillis();
if (timestamp < lastTimestamp) {
// 如果当前时间小于上次生成 ID 的时间戳,说明系统时钟回退过,抛出异常
throw new RuntimeException("Clock moved backwards. Refusing to generate ID");
}
if (timestamp == lastTimestamp) {
// 如果当前时间等于上次生成 ID 的时间戳,说明同一毫秒内生成了多个 ID,需要进行序列号的累加
sequence = (sequence + 1) & MAX_SEQUENCE;
if (sequence == 0L) {
// 序列号已经超过最大值,等待下一毫秒再生成 ID
timestamp = waitNextMillis(lastTimestamp);
}
} else {
// 如果当前时间大于上次生成 ID 的时间戳,说明已经进入下一毫秒,序列号重置为0
sequence = 0L;
}
// 更新上次生成 ID 的时间戳
lastTimestamp = timestamp;
// 生成 ID
return ((timestamp - START_TIME) << TIMESTAMP_LEFT_SHIFT) |
(dataCenterId << DATA_CENTER_ID_SHIFT) |
(workerId << WORKER_ID_SHIFT) |
sequence;
}
/**
* 循环等待到下一毫秒
*
* @param lastTimestamp 上次生成 ID 的时间戳
* @return long
*/
private long waitNextMillis(long lastTimestamp) {
long timestamp = System.currentTimeMillis();
while (timestamp <= lastTimestamp) {
timestamp = System.currentTimeMillis();
}
return timestamp;
}
public static void main(String[] args) {
Snowflake snowflake = new Snowflake(new Random().nextInt((int) MAX_WORKER_ID), new Random().nextInt((int) MAX_DATA_CENTER_ID));
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
for (int i = 0; i < 10; i++) {
long id = snowflake.nextId();
String time = dateFormat.format(new Date((id >> TIMESTAMP_LEFT_SHIFT) + START_TIME));
System.out.printf("%s workerId %d dataCenterId %d sequence %d\n", time, (id >> WORKER_ID_SHIFT) & MAX_WORKER_ID, (id >> DATA_CENTER_ID_SHIFT) & MAX_DATA_CENTER_ID, id & MAX_SEQUENCE);
}
}
}
```
这是一个基于 Twitter 的雪花算法的实现,可以生成全局唯一、有序的 64 位长整型 ID。在上面的代码中,我们使用了当前时间戳、机器 ID、数据标识 ID 和序列号这四个参数来生成 ID,其中机器 ID 和数据标识 ID 可以通过构造函数传递进来。
如果有任何疑问,请随时告诉我。
阅读全文