Java实现雪花算法(snowflake)
本文主要介绍了Java实现雪花算法(snowflake),分享给大家,具体如下:
简单描述
最高位是符号位,始终为0,不可用。
- 41位的时间序列,精确到毫秒级,41位的长度可以使用69年。时间位还有一个很重要的作用是可以根据时间进行排序。注意,41位时间截不是存储当前时间的时间截,而是存储时间截的差值(当前时间截-开始时间截)后得到的值,这里的的开始时间截,一般是我们的id生成器开始使用的时间,由我们程序来指定的(如下下面程序SnowFlake类的START_STMP属性)。41位的时间截,可以使用69年,年T=(1L<<41)/(1000L*60*60*24*365)=69
- 10位的机器标识,10位的长度最多支持部署1024个节点。
- 12位的计数序列号,序列号即一系列的自增id,可以支持同一节点同一毫秒生成多个ID序号,12位的计数序列号支持每个节点每毫秒产生4096个ID序号。
加起来刚好64位,为一个Long型。这个算法很简洁,但依旧是一个很好的ID生成策略。其中,10位器标识符一般是5位IDC+5位machine编号,唯一确定一台机器。
算法实现
publicclassSnowFlake{ //起始的时间戳 privatefinalstaticlongSTART_STMP=1577808000000L;//2020-01-01 //每一部分占用的位数,就三个 privatefinalstaticlongSEQUENCE_BIT=12;//序列号占用的位数 privatefinalstaticlongMACHINE_BIT=5;//机器标识占用的位数 privatefinalstaticlongDATACENTER_BIT=5;//数据中心占用的位数 //每一部分最大值 privatefinalstaticlongMAX_DATACENTER_NUM=-1L^(-1L<MAX_DATACENTER_NUM||datacenterId<0){ thrownewIllegalArgumentException("datacenterIdcan'tbegreaterthanMAX_DATACENTER_NUMorlessthan0"); } if(machineId>MAX_MACHINE_NUM||machineId<0){ thrownewIllegalArgumentException("machineIdcan'tbegreaterthanMAX_MACHINE_NUMorlessthan0"); } this.datacenterId=datacenterId; this.machineId=machineId; } //产生下一个ID publicsynchronizedlongnextId(){ longcurrStmp=timeGen(); if(currStmp lastTimestamp,说明本次调用跟上次调用对比,已经不再同一个毫秒内了,这个时候序号可以重新回置0了。 sequence=0L; } lastStmp=currStmp; //就是用相对毫秒数、机器ID和自增序号拼接 return(currStmp-START_STMP)< 当增加一秒生成ID的时候就是增加10位的机器标识+12位序列+约2的10次方(1000毫秒),最终就是增加一个2的32次方4294967296就是42亿左右
但是这里有一个坑,雪花算法产生的长整数的精度可能超过javascript能表达的精度,这会导致js获取的id与雪花算法算出来的id不一致,如雪花算法得到的是36594866121080832,但是因为javascript丢失精度后只获取到36594866121080830,这会导致对数据的所有操作都失效。
解决办法:后端的语言获取到雪花算法的id后将其转换为String类型,这样js也会当做字符串来处理,就不会丢失精度了。
配置方法
@Configuration publicclassWebMvcConfigimplementsWebMvcConfigurer{ @Autowired publicvoidconfigureMessageConverters(List>converters){ converters.add(toStringConverter()); } /** *BigDecimalLong转化为String * *@return */ @Bean publicMappingJackson2HttpMessageConvertertoStringConverter(){ MappingJackson2HttpMessageConverterconverter=newMappingJackson2HttpMessageConverter(); ObjectMappermapper=newObjectMapper(); SimpleModulesimpleModule=newSimpleModule(); simpleModule.addSerializer(BigDecimal.class,BigDecimalToStringSerializer.instance); simpleModule.addSerializer(Long.class,ToStringSerializer.instance); simpleModule.addSerializer(Long.TYPE,ToStringSerializer.instance); simpleModule.addSerializer(long.class,ToStringSerializer.instance); mapper.registerModule(simpleModule); //Include.Include.ALWAYS默认 //Include.NON_DEFAULT属性为默认值不序列化 //Include.NON_EMPTY属性为空("")或者为NULL都不序列化,则返回的json是没有这个字段的。这样对移动端会更省流量 //Include.NON_NULL属性为NULL不序列化 mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false); mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS,true);//允许出现特殊字符和转义符 mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES,true);//允许出现单引号 converter.setObjectMapper(mapper); returnconverter; } @JacksonStdImpl staticclassBigDecimalToStringSerializerextendsToStringSerializer{ publicfinalstaticBigDecimalToStringSerializerinstance=newBigDecimalToStringSerializer(); publicBigDecimalToStringSerializer(){ super(Object.class); } publicBigDecimalToStringSerializer(Class>handledType){ super(handledType); } @Override publicbooleanisEmpty(SerializerProviderprov,Objectvalue){ if(value==null){ returntrue; } Stringstr=((BigDecimal)value).stripTrailingZeros().toPlainString(); returnstr.isEmpty(); } @Override publicvoidserialize(Objectvalue,JsonGeneratorgen,SerializerProviderprovider) throwsIOException{ gen.writeString(((BigDecimal)value).stripTrailingZeros().toPlainString()); } @Override publicJsonNodegetSchema(SerializerProviderprovider,TypetypeHint)throwsJsonMappingException{ returncreateSchemaNode("string",true); } @Override publicvoidserializeWithType(Objectvalue,JsonGeneratorgen, SerializerProviderprovider,TypeSerializertypeSer) throwsIOException{ //notypeinfo,justregularserialization serialize(value,gen,provider); } } } 到此这篇关于Java实现雪花算法(snowflake)的文章就介绍到这了,更多相关Java雪花算法内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。