Java實(shí)現(xiàn)雪花算法(snowflake)
本文主要介紹了Java實(shí)現(xiàn)雪花算法(snowflake),分享給大家,具體如下:

簡(jiǎn)單描述
最高位是符號(hào)位,始終為0,不可用。
41位的時(shí)間序列,精確到毫秒級(jí),41位的長(zhǎng)度可以使用69年。時(shí)間位還有一個(gè)很重要的作用是可以根據(jù)時(shí)間進(jìn)行排序。注意,41位時(shí)間截不是存儲(chǔ)當(dāng)前時(shí)間的時(shí)間截,而是存儲(chǔ)時(shí)間截的差值(當(dāng)前時(shí)間截 - 開(kāi)始時(shí)間截) 后得到的值,這里的的開(kāi)始時(shí)間截,一般是我們的id生成器開(kāi)始使用的時(shí)間,由我們程序來(lái)指定的(如下下面程序SnowFlake類的START_STMP屬性)。41位的時(shí)間截,可以使用69年,年T = (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69 10位的機(jī)器標(biāo)識(shí),10位的長(zhǎng)度最多支持部署1024個(gè)節(jié)點(diǎn)。 12位的計(jì)數(shù)序列號(hào),序列號(hào)即一系列的自增id,可以支持同一節(jié)點(diǎn)同一毫秒生成多個(gè)ID序號(hào),12位的計(jì)數(shù)序列號(hào)支持每個(gè)節(jié)點(diǎn)每毫秒產(chǎn)生4096個(gè)ID序號(hào)。加起來(lái)剛好64位,為一個(gè)Long型。這個(gè)算法很簡(jiǎn)潔,但依舊是一個(gè)很好的ID生成策略。其中,10位器標(biāo)識(shí)符一般是5位IDC+5位machine編號(hào),唯一確定一臺(tái)機(jī)器。
算法實(shí)現(xiàn)
public class SnowFlake { // 起始的時(shí)間戳 private final static long START_STMP = 1577808000000L; //2020-01-01 // 每一部分占用的位數(shù),就三個(gè) private final static long SEQUENCE_BIT = 12; //序列號(hào)占用的位數(shù) private final static long MACHINE_BIT = 5; //機(jī)器標(biāo)識(shí)占用的位數(shù) private final static long DATACENTER_BIT = 5; //數(shù)據(jù)中心占用的位數(shù) // 每一部分最大值 private final static long MAX_DATACENTER_NUM = -1L ^ (-1L << DATACENTER_BIT); private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT); private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT); // 每一部分向左的位移 private final static long MACHINE_LEFT = SEQUENCE_BIT; private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT; private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT; private long datacenterId; //數(shù)據(jù)中心 private long machineId; //機(jī)器標(biāo)識(shí) private long sequence = 0L; //序列號(hào) private long lastStmp = -1L; //上一次時(shí)間戳 public SnowFlake(long datacenterId, long machineId) { if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) { throw new IllegalArgumentException('datacenterId can’t be greater than MAX_DATACENTER_NUM or less than 0'); } if (machineId > MAX_MACHINE_NUM || machineId < 0) { throw new IllegalArgumentException('machineId can’t be greater than MAX_MACHINE_NUM or less than 0'); } this.datacenterId = datacenterId; this.machineId = machineId; } //產(chǎn)生下一個(gè)ID public synchronized long nextId() { long currStmp = timeGen(); if (currStmp < lastStmp) { throw new RuntimeException('Clock moved backwards. Refusing to generate id'); } if (currStmp == lastStmp) { //if條件里表示當(dāng)前調(diào)用和上一次調(diào)用落在了相同毫秒內(nèi),只能通過(guò)第三部分,序列號(hào)自增來(lái)判斷為唯一,所以+1. sequence = (sequence + 1) & MAX_SEQUENCE; //同一毫秒的序列數(shù)已經(jīng)達(dá)到最大,只能等待下一個(gè)毫秒 if (sequence == 0L) { currStmp = getNextMill(); } } else { //不同毫秒內(nèi),序列號(hào)置為0 //執(zhí)行到這個(gè)分支的前提是currTimestamp > lastTimestamp,說(shuō)明本次調(diào)用跟上次調(diào)用對(duì)比,已經(jīng)不再同一個(gè)毫秒內(nèi)了,這個(gè)時(shí)候序號(hào)可以重新回置0了。 sequence = 0L; } lastStmp = currStmp; //就是用相對(duì)毫秒數(shù)、機(jī)器ID和自增序號(hào)拼接 return (currStmp - START_STMP) << TIMESTMP_LEFT //時(shí)間戳部分 | datacenterId << DATACENTER_LEFT //數(shù)據(jù)中心部分 | machineId << MACHINE_LEFT //機(jī)器標(biāo)識(shí)部分 | sequence;//序列號(hào)部分 } private long getNextMill() { long mill = timeGen(); while (mill <= lastStmp) { mill = timeGen(); } return mill; } private long timeGen() { return System.currentTimeMillis(); }}
當(dāng)增加一秒生成ID的時(shí)候就是增加10位的機(jī)器標(biāo)識(shí)+12位序列+約2的10次方(1000毫秒),最終就是增加一個(gè)2的32次方4 294 967 296就是42億左右
但是這里有一個(gè)坑,雪花算法產(chǎn)生的長(zhǎng)整數(shù)的精度可能超過(guò)javascript能表達(dá)的精度,這會(huì)導(dǎo)致js獲取的id與雪花算法算出來(lái)的id不一致,如雪花算法得到的是36594866121080832,但是因?yàn)閖avascript丟失精度后只獲取到36594866121080830, 這會(huì)導(dǎo)致對(duì)數(shù)據(jù)的所有操作都失效。
解決辦法:后端的語(yǔ)言獲取到雪花算法的id后將其轉(zhuǎn)換為String類型,這樣js也會(huì)當(dāng)做字符串來(lái)處理,就不會(huì)丟失精度了。
配置方法
@Configurationpublic class WebMvcConfig implements WebMvcConfigurer { @Autowired public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { converters.add(toStringConverter()); } /** * BigDecimal Long 轉(zhuǎn)化為String * * @return */ @Bean public MappingJackson2HttpMessageConverter toStringConverter() { MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); ObjectMapper mapper = new ObjectMapper(); SimpleModule simpleModule = new SimpleModule(); 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 默認(rèn) // Include.NON_DEFAULT 屬性為默認(rèn)值不序列化 // Include.NON_EMPTY 屬性為 空('') 或者為 NULL 都不序列化,則返回的json是沒(méi)有這個(gè)字段的。這樣對(duì)移動(dòng)端會(huì)更省流量 // 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);// 允許出現(xiàn)特殊字符和轉(zhuǎn)義符 mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); // 允許出現(xiàn)單引號(hào) converter.setObjectMapper(mapper); return converter; } @JacksonStdImpl static class BigDecimalToStringSerializer extends ToStringSerializer { public final static BigDecimalToStringSerializer instance = new BigDecimalToStringSerializer(); public BigDecimalToStringSerializer() { super(Object.class); } public BigDecimalToStringSerializer(Class<?> handledType) { super(handledType); } @Override public boolean isEmpty(SerializerProvider prov, Object value) { if (value == null) { return true; } String str = ((BigDecimal) value).stripTrailingZeros().toPlainString(); return str.isEmpty(); } @Override public void serialize(Object value, JsonGenerator gen, SerializerProvider provider) throws IOException { gen.writeString(((BigDecimal) value).stripTrailingZeros().toPlainString()); } @Override public JsonNode getSchema(SerializerProvider provider, Type typeHint) throws JsonMappingException { return createSchemaNode('string', true); } @Override public void serializeWithType(Object value, JsonGenerator gen, SerializerProvider provider, TypeSerializer typeSer) throws IOException { // no type info, just regular serialization serialize(value, gen, provider); } }}
到此這篇關(guān)于Java實(shí)現(xiàn)雪花算法(snowflake)的文章就介紹到這了,更多相關(guān)Java 雪花算法內(nèi)容請(qǐng)搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!
相關(guān)文章:
1. asp.net core服務(wù)限制堆內(nèi)存大小的操作方法2. 解決Django響應(yīng)JsonResponse返回json格式數(shù)據(jù)報(bào)錯(cuò)問(wèn)題3. python 制作python包,封裝成可用模塊教程4. Python爬取12306車次信息代碼詳解5. 通過(guò)vue如何設(shè)置header6. Java基礎(chǔ)之詳解HashSet的使用方法7. python怎么運(yùn)行代碼8. 詳解Java String類常用方法有哪些9. Python 實(shí)現(xiàn)將某一列設(shè)置為str類型10. Python使用paramiko連接遠(yuǎn)程服務(wù)器執(zhí)行Shell命令的實(shí)現(xiàn)

網(wǎng)公網(wǎng)安備