最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java實(shí)現(xiàn)雪花算法(snowflake)

 更新時(shí)間:2020年08月26日 10:26:34   作者:xuanm  
這篇文章主要介紹了Java實(shí)現(xiàn)雪花算法(snowflake),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

本文主要介紹了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ì)丟失精度了。

配置方法

@Configuration
public 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)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java Class 解析器實(shí)現(xiàn)方法示例

    Java Class 解析器實(shí)現(xiàn)方法示例

    這篇文章主要通過(guò)對(duì)class文件的分析,介紹了Java Class 解析器實(shí)現(xiàn)方法示例,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-09-09
  • 解析Java的Spring框架的BeanPostProcessor發(fā)布處理器

    解析Java的Spring框架的BeanPostProcessor發(fā)布處理器

    這篇文章主要介紹了Java的Spring框架的BeanPostProcessor發(fā)布處理器,Spring是Java的SSH三大web開(kāi)發(fā)框架之一,需要的朋友可以參考下
    2015-12-12
  • java集合 ArrayDeque源碼詳細(xì)分析

    java集合 ArrayDeque源碼詳細(xì)分析

    ArrayDeque是一種以數(shù)組方式實(shí)現(xiàn)的雙端隊(duì)列,它是非線程安全的。下面小編和大家一起學(xué)習(xí)一下
    2019-05-05
  • java微信公眾號(hào)開(kāi)發(fā)第一步 公眾號(hào)接入和access_token管理

    java微信公眾號(hào)開(kāi)發(fā)第一步 公眾號(hào)接入和access_token管理

    這篇文章主要為大家介紹了java微信公眾號(hào)開(kāi)發(fā),主要內(nèi)容包括公眾號(hào)接入和access_token管理,感興趣的小伙伴們可以參考一下
    2016-01-01
  • 數(shù)據(jù)庫(kù)連接超時(shí)java處理的兩種方式

    數(shù)據(jù)庫(kù)連接超時(shí)java處理的兩種方式

    這篇文章主要介紹了數(shù)據(jù)庫(kù)連接超時(shí)java處理的兩種方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • SpringBoot無(wú)法識(shí)別bootstrap.yml小綠葉問(wèn)題的解決辦法

    SpringBoot無(wú)法識(shí)別bootstrap.yml小綠葉問(wèn)題的解決辦法

    一般單獨(dú)使用?Spring?Boot?時(shí),bootstrap.yml?文件一般是不會(huì)生效的,也就是沒(méi)有小綠葉圖標(biāo),本文給大家介紹了SpringBoot無(wú)法識(shí)別bootstrap.yml小綠葉問(wèn)題的解決辦法,文中給出了兩種解決方案,需要的朋友可以參考下
    2024-07-07
  • JRebel2023.3 插件使用及安裝步驟詳解

    JRebel2023.3 插件使用及安裝步驟詳解

    JRebel是一款JVM插件,它使得Java代碼修改后不用重啟系統(tǒng),立即生效,IDEA上原生是不支持熱部署的,一般更新了 Java 文件后要手動(dòng)重啟 Tomcat 服務(wù)器,才能生效,浪費(fèi)時(shí)間浪費(fèi)生命,目前對(duì)于idea熱部署最好的解決方案就是安裝JRebel插件,本文分步驟介紹的非常詳細(xì),一起看看吧
    2023-08-08
  • java仿windows記事本小程序

    java仿windows記事本小程序

    這篇文章主要為大家詳細(xì)介紹了java仿windows記事本小程序,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-03-03
  • 詳解自動(dòng)注冊(cè)Gateway網(wǎng)關(guān)路由配置

    詳解自動(dòng)注冊(cè)Gateway網(wǎng)關(guān)路由配置

    這篇文章主要為大家介紹了自動(dòng)注冊(cè)Gateway網(wǎng)關(guān)路由配置的方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • java通過(guò)snmp協(xié)議獲取物理設(shè)備信息

    java通過(guò)snmp協(xié)議獲取物理設(shè)備信息

    這篇文章主要介紹了java通過(guò)snmp協(xié)議獲取物理設(shè)備信息,snmp中文含義是簡(jiǎn)單網(wǎng)絡(luò)管理協(xié)議,可用完成對(duì)計(jì)算機(jī)、路由器和其他網(wǎng)絡(luò)設(shè)備的遠(yuǎn)程管理和監(jiān)視,本文我們是通過(guò)java程序來(lái)獲取,需要的朋友可以參考下
    2023-07-07

最新評(píng)論

康定县| 普宁市| 驻马店市| 福海县| 沂水县| 丰都县| 泽普县| 车致| 襄垣县| 全州县| 保定市| 阿克| 天门市| 六枝特区| 昌都县| 阜新市| 开原市| 棋牌| 汶川县| 太康县| 沁水县| 基隆市| 工布江达县| 咸宁市| 新兴县| 尚义县| 昭觉县| 景德镇市| 翁牛特旗| 山西省| 凤城市| 深圳市| 千阳县| 论坛| 齐齐哈尔市| 利津县| 横山县| 静海县| 剑河县| 墨竹工卡县| 修水县|