java使用bitmap實(shí)現(xiàn)可回收自增id的示例
需求描述
設(shè)計(jì)一個(gè)方法,每次調(diào)用返回一個(gè)自增id,同時(shí)需要滿足以下要求。
- 可更新id的狀態(tài)為已使用,已使用的id下次調(diào)用時(shí)不再返回
- 可修改某個(gè)id的狀態(tài)為未使用,下次調(diào)用時(shí)設(shè)為未使用狀態(tài)的id可重新被返回
思路
思路一:如果數(shù)據(jù)量非常小,直接使用一個(gè)集合存儲(chǔ)已使用的id,使用循環(huán)和維護(hù)這個(gè)集合即可,但數(shù)據(jù)量大了,此方法返回?cái)?shù)據(jù)的時(shí)間復(fù)雜度和占用的空間都是比較大的。
思路二(推薦):建立一個(gè)(位圖)bitmap,初始時(shí)bitmap的每一位都為0,0代表未使用,1代表已使用。每次請(qǐng)求獲取id時(shí)從此bitmap的第0位開始返回一個(gè)未使用的index即可。
以一個(gè)bitmap長度為65536的bitmap為例,示意圖如下:
初始時(shí)每一個(gè)bit位值都為0
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | …… | 1024 | …… | 65535 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | …… | 0 | …… | 0 |
此時(shí)請(qǐng)求id返回的值為:0
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | …… | 1024 | …… | 65535 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | …… | 1 | …… | 0 |
如經(jīng)過一段時(shí)間后,索引位置為5的數(shù)據(jù)變成了0未使用
此時(shí)請(qǐng)求id返回的值應(yīng)為:5
具體實(shí)現(xiàn)
BitSet VS RoaringBitmap
解決思路有了,接下來就是代碼實(shí)現(xiàn)。這里以java代碼為例,可以直接使用jdk自帶的java.util.BitSet實(shí)現(xiàn),不過自帶的BitSet在數(shù)據(jù)稀疏的場景下占用空間較大,且提供的原生方法較少。
這里推薦直接使用由2016年由幾位大佬論文而開發(fā)的RoaringBitmap,可移步它的官網(wǎng)詳細(xì)學(xué)習(xí)一把。https://roaringbitmap.org/about/
RoaringBitmap有java、go、c\c++、rust、swift等多個(gè)版本的實(shí)現(xiàn),同時(shí)其時(shí)間與空間復(fù)雜度低,提供的方法也非常豐富。
github地址如下:https://github.com/RoaringBitmap
java代碼實(shí)現(xiàn)
以下為《使用bitmap實(shí)現(xiàn)可回收自增id》的示例代碼
引入依賴
<dependency> <groupId>org.roaringbitmap</groupId> <artifactId>RoaringBitmap</artifactId> <version>1.0.0</version> </dependency>
示例代碼:
public static void main(String[] args) { RoaringBitmap rr = new RoaringBitmap(); long l = rr.nextAbsentValue(0); System.out.println(l);//print 0 rr.add(0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 1024, 1025); l = rr.nextAbsentValue(0); System.out.println(l);//print 5 // index 5 set true(1) rr.add(5); l = rr.nextAbsentValue(0); System.out.println(l);//print 11 }
輸出結(jié)果:
0
5
11
以上代碼使用new RoaringBitmap()定義了一個(gè)可以自動(dòng)擴(kuò)容的bitmap,add方法的入?yún)⒋韺⒛硞€(gè)bit位設(shè)為1,nextAbsentValue方法返回從某個(gè)index位開始出現(xiàn)的第一個(gè)bit位為0的索引值
分布式自增可回收id實(shí)現(xiàn)方案
RoaringBitmap還有一大特點(diǎn):支持序列化與反序列化。
憑借這一特點(diǎn),如需要在分布式場景下使用RoaringBitmap,則僅需稍微修改代碼即可快速實(shí)現(xiàn)。
如將RoaringBitmap序列化為二進(jìn)制存儲(chǔ)在數(shù)據(jù)庫中。
比如在mongodb中使用Binary data數(shù)據(jù)類型、mysql中使用blob數(shù)據(jù)類型、oracle中使用BLOB這些二進(jìn)制類型存儲(chǔ)RoaringBitmap即可。
實(shí)現(xiàn)時(shí)每次先將RoaringBitmap讀取到程序中,再進(jìn)行邏輯操作,修改后再寫回?cái)?shù)據(jù)庫中。
總結(jié)一下
RoaringBitmap YYDS
到此這篇關(guān)于java使用bitmap實(shí)現(xiàn)可回收自增id的示例的文章就介紹到這了,更多相關(guān)java 可回收自增id內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Java Base64位編碼與String字符串的相互轉(zhuǎn)換,Base64與Bitmap的相互轉(zhuǎn)換實(shí)例代碼
- 海量數(shù)據(jù)去重排序bitmap(位圖法)在java中實(shí)現(xiàn)的兩種方法
- redis?bitmap數(shù)據(jù)結(jié)構(gòu)之java對(duì)等操作詳解
- Java中利用BitMap位圖實(shí)現(xiàn)海量級(jí)數(shù)據(jù)去重
- java實(shí)現(xiàn)用戶簽到BitMap功能實(shí)現(xiàn)demo
- Java?BitMap源碼仿寫實(shí)現(xiàn)
- Java位集合之BitMap實(shí)現(xiàn)和應(yīng)用詳解
相關(guān)文章
Java中的CyclicBarrier、CountDownLatch和Semaphore的具體使用
本文主要介紹了Java中的CyclicBarrier、CountDownLatch和Semaphore的具體使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-05-05Arthas排查Kubernetes中應(yīng)用頻繁掛掉重啟異常
這篇文章主要為大家介紹了Arthas排查Kubernetes中應(yīng)用頻繁掛掉重啟的異常分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助祝大家多多進(jìn)步2022-02-02springboot基于過濾器實(shí)現(xiàn)接口請(qǐng)求耗時(shí)統(tǒng)計(jì)操作
這篇文章主要介紹了springboot基于過濾器實(shí)現(xiàn)接口請(qǐng)求耗時(shí)統(tǒng)計(jì)操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-09-09Spring?Security如何實(shí)現(xiàn)升級(jí)密碼加密方式詳解
這篇文章主要為大家介紹了Spring?Security實(shí)現(xiàn)升級(jí)密碼加密方式詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01SpringBoot 關(guān)于Feign的超時(shí)時(shí)間配置操作
這篇文章主要介紹了SpringBoot 關(guān)于Feign的超時(shí)時(shí)間配置操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09Java設(shè)計(jì)模式以虹貓藍(lán)兔的故事講解代理模式
代理模式是Java常見的設(shè)計(jì)模式之一。所謂代理模式是指客戶端并不直接調(diào)用實(shí)際的對(duì)象,而是通過調(diào)用代理,來間接的調(diào)用實(shí)際的對(duì)象2022-04-04淺談java 字符串,字符數(shù)組,list間的轉(zhuǎn)化
下面小編就為大家?guī)硪黄獪\談java 字符串,字符數(shù)組,list間的轉(zhuǎn)化。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-11-11基于獲取JAVA路徑,包括CLASSPATH外的路徑的方法詳解
本篇文章是對(duì)獲取JAVA路徑,包括CLASSPATH外的路徑的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05