首页 文章 精选 留言 我的

精选列表

搜索[高并发],共10000篇文章
优秀的个人博客,低调大师

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

我们设计数据表的时候,一般都会有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(); } } 测试结果

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册