实现逻辑很简单的
雪花算法是产生一个long类型的id
long是个64位的类型
毫秒级的时间戳占了41位,我这里代码是使用java里获取的毫秒时间戳,最大可以用到2039-09-07 23:47:35
你也可以定义一个开始使用的日期,然后,当前时间-开始使用的日期,用这一个值作为时间戳
机器码,占了10位
序列数,占了12位
id = 把时间戳的值左位移动22(机器码占用长度+序列数占用长度)| 机器码的值左位移动 12(序列数占用长度)| 序列数
至于时间回拨等问题,我这里只是抛出了异常
1.你可以等待一下,让系统的时间追上来,如果还是追不上,那是只能抛出异常了,让rb让系统的时钟回拨
2.可以设置一个扩展的位置,如果时间回拨,扩展位+1,如果扩展位都满了,那是只能抛出异常了,让rb让系统的时钟回拨
package com.gcno93.study.zookeeper.util;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
/**
* 使用64位
* 第一位为0不使用
* 第2到42位,毫秒时间戳,总共41位 最大值 2199023255551
* 第43位到52位为机器码 总共10位 最大值1023
* 第53位到64位为序列号 总共12位 最大值4095
* 产生一个long类型
* @author lwh
* @date 2022/1/19
*/
public final class SnowFlake {
private long workerId;
public SnowFlake(long workerId) {
if(workerId<0 || workerId> MAX_WORKER_ID){
throw new IllegalArgumentException("workerId 只能 0<workerId<1023");
}
this.workerId = workerId;
}
private final static int MAX_SEQUENCE = 4095;
private final static int MAX_WORKER_ID = 1023;
private final static int SEQUENCE_BIT_LEN = 12;
private final static int WORKER_ID_BIT_LEN = 10;
private final static int WORKER_ID_SHIFT= SEQUENCE_BIT_LEN;
private final static int Time_SHIFT= WORKER_ID_BIT_LEN + SEQUENCE_BIT_LEN;
private long lastTime;
private int sequence;
public synchronized Long next(){
//当前时间
long currentTime = System.currentTimeMillis();
//时间回拨的问题
if(lastTime > currentTime){
throw new RuntimeException("时间回拨");
}
//当大于最大值时
if(sequence>=MAX_SEQUENCE){
if(currentTime == lastTime){
//等待1毫秒
try {
wait(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//重新赋值
sequence = 0;
currentTime = System.currentTimeMillis();
}
}
long woker = workerId<<WORKER_ID_SHIFT;
final long time = currentTime << Time_SHIFT;
return time| woker| ++sequence;
}
public static void main(String[] args) throws InterruptedException {
Set<Long> ids = Collections.synchronizedSet(new HashSet<>());
CountDownLatch cd = new CountDownLatch(1000000);
final SnowFlake snowFlake = new SnowFlake(123);
for (int i = 0; i < 1000000; i++) {
new Thread(new Runnable() {
@Override
public void run() {
final Long id = snowFlake.next();
if(ids.contains(id)){
System.out.println(id);
}
ids.add(snowFlake.next());
cd.countDown();
}
}).start();
}
cd.await();
System.out.println(ids.size());
}
}
网友评论