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長(zhǎng)度為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)過(guò)一段時(shí)間后,索引位置為5的數(shù)據(jù)變成了0未使用
此時(shí)請(qǐng)求id返回的值應(yīng)為:5
具體實(shí)現(xiàn)
BitSet VS RoaringBitmap
解決思路有了,接下來(lái)就是代碼實(shí)現(xiàn)。這里以java代碼為例,可以直接使用jdk自帶的java.util.BitSet實(shí)現(xiàn),不過(guò)自帶的BitSet在數(shù)據(jù)稀疏的場(chǎng)景下占用空間較大,且提供的原生方法較少。
這里推薦直接使用由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),如需要在分布式場(chǎng)景下使用RoaringBitmap,則僅需稍微修改代碼即可快速實(shí)現(xiàn)。
如將RoaringBitmap序列化為二進(jìn)制存儲(chǔ)在數(shù)據(jù)庫(kù)中。
比如在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ù)庫(kù)中。
總結(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)文章
SpringCloud Gateway路由表配置實(shí)現(xiàn)小結(jié)
SpringCloudGateway通過(guò)路由表將請(qǐng)求轉(zhuǎn)發(fā)到不同的服務(wù)或地址,每個(gè)路由包含id、uri、predicates和filters等字段,下面就來(lái)介紹一下SpringCloud Gateway路由如何配置,感興趣的可以了解一下2026-01-01
SpringBoot實(shí)現(xiàn)單點(diǎn)登錄(SSO)的四種方案
單點(diǎn)登錄(Single?Sign-On,SSO)是企業(yè)應(yīng)用系統(tǒng)中常見(jiàn)的用戶認(rèn)證方案,它允許用戶使用一組憑證訪問(wèn)多個(gè)相關(guān)但獨(dú)立的系統(tǒng),無(wú)需重復(fù)登錄,本文給大家介紹了SpringBoot實(shí)現(xiàn)單點(diǎn)登錄(SSO)的四種方案,需要的朋友可以參考下2025-04-04
Java實(shí)現(xiàn)ByteArray與String互轉(zhuǎn)的常見(jiàn)轉(zhuǎn)換方法
在現(xiàn)代 Java 開發(fā)中,處理字節(jié)數(shù)據(jù)(byte[])和字符串(String)之間的轉(zhuǎn)換是一項(xiàng)常見(jiàn)且至關(guān)重要的任務(wù),無(wú)論是網(wǎng)絡(luò)通信、文件操作、加密解密還是序列化反序列化,我們都需要在 byte[] 和 String 之間進(jìn)行高效、準(zhǔn)確的轉(zhuǎn)換,所以本文介紹了ByteArray與String互轉(zhuǎn)方法2025-12-12
spring boot如何使用spring AOP實(shí)現(xiàn)攔截器
本篇文章主要介紹了spring boot如何使用spring AOP實(shí)現(xiàn)攔截器,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-04-04

