温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

怎么实现缩小版雪花算法与多线程并发测试

发布时间:2021-10-23 15:37:33 来源:亿速云 阅读:557 作者:iii 栏目:编程语言

这篇文章主要讲解了“怎么实现缩小版雪花算法与多线程并发测试”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么实现缩小版雪花算法与多线程并发测试”吧!

我们设计数据表的时候,一般都会有ID字段,ID的生成方法有多种,比如数据库自增,UUID,雪花算法等。

考虑到以后数据的增长,分库分表,分布式等要求,我们选择雪花算法来生成ID。

开发Web系统需要后端跟前端交互,前端JavaScript支持的最大整型是53位,超过53位会丢失精度,原版的雪花算法会超过53位,我们使用缩小版的雪花算法,把位数减小到53位。

原版Snowflake算法的极限是每毫秒的每一个节点生成4059个id值,也就是说每毫秒的极限是生成023*4059=4 152 357个id值 ,缩小后极限是每秒生成15*131071=1 966 065个分布式id,够我们在开发里面的日常使用了。

package cn.gintone.asso.util;

/**
 * @description:缩小版的雪花算法
 * @author:Elon He
 * @create:2020-10-06
 */
public class SnowflakeMini {
    /**
     * 开始时间截 (1970-01-01)
     */
    private final static long twepoch = 0L;
    /**
     * 机器id,范围是1到15
     */
    private final static long workerId =1L;
    /**
     * 机器id所占的位数,占4位
     */
    private final static long workerIdBits = 4L;
    /**
     * 支持的最大机器id,结果是15
     */
    private final static long maxWorkerId = ~(-1L << workerIdBits);
    /**
     * 生成序列占的位数
     */
    private final static long sequenceBits = 15L;
    /**
     * 机器ID向左移15位
     */
    private final static long workerIdShift = sequenceBits;
    /**
     * 生成序列的掩码,这里为最大是32767 (1111111111111=32767)
     */
    private final static long sequenceMask = ~(-1L << sequenceBits);
    /**
     * 时间截向左移19位(4+15)
     */
    private final static long timestampLeftShift = 19L;
    /**
     * 秒内序列(0~32767)
     */
    private static long sequence = 0L;
    /**
     * 上次生成ID的时间截
     */
    private static long lastTimestamp = -1L;

    /**
     * 获得下一个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;
        //黄色代码注释开始
        //移位并通过或运算拼到一起组成53 位的ID
        return ((timestamp - twepoch) << timestampLeftShift)
                | (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()/1000L;
    }

}

创建两个线程,同时测试ID获取。
测试线程类A

package cn.gintone.asso;


import cn.gintone.asso.util.SnowflakeMini;

/**
 * @description:线程A
 * @author:Elon He
 * @create:2020-10-06
 */
public class ThreadA extends Thread{

    @Override
    public void run() {
        super.run();
        for (int i = 0; i < 10; i++) {
            long id = SnowflakeMini.nextId();
            System.out.println("A:"+id);
        }
    }
}

测试线程类B

package cn.gintone.asso;

import cn.gintone.asso.util.SnowflakeMini;

/**
 * @description:线程B
 * @author:Elon He
 * @create:2020-10-06
 */
public class ThreadB extends  Thread{

    @Override
    public void run() {
        super.run();
        for (int i = 0; i < 10; i++) {
            long id = SnowflakeMini.nextId();
            System.out.println("B:"+id);
        }
    }
}

测试类(注释掉的代码是修改成静态方法前的测试方法)

package cn.gintone.asso;

/**
 * @description:雪花算法测试类
 * @author:Elon He
 * @create:2020-10-06
 */
public class TestSnowflake {
    public static void main(String[] args) {
        //不同线程使用同一个对象,不重复
//        SnowflakeMini idWorker = new SnowflakeMini(0);
//        ThreadA t1 = new ThreadA(idWorker);
//        ThreadB t2 = new ThreadB(idWorker);
//        t1.start();
//        t2.start();
        //不同线程使用不同对象,会重复
//        SnowflakeMini idWorker1 = new SnowflakeMini(0);
//        SnowflakeMini idWorker2 = new SnowflakeMini(0);
//        ThreadA t1 = new ThreadA(idWorker1);
//        ThreadB t2 = new ThreadB(idWorker2);
//        t1.start();
//        t2.start();

        //nextId修改成静态方法后测试,不重复
        ThreadA t1 = new ThreadA();
        ThreadB t2 = new ThreadB();
        t1.start();
        t2.start();

    }
}

测试结果

怎么实现缩小版雪花算法与多线程并发测试

感谢各位的阅读,以上就是“怎么实现缩小版雪花算法与多线程并发测试”的内容了,经过本文的学习后,相信大家对怎么实现缩小版雪花算法与多线程并发测试这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI