美文网首页
snowflake java版本

snowflake java版本

作者: gcno93 | 来源:发表于2022-01-20 01:42 被阅读0次

实现逻辑很简单的
雪花算法是产生一个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());
    }


}

相关文章

网友评论

      本文标题:snowflake java版本

      本文链接:https://www.haomeiwen.com/subject/kqodhrtx.html