Redis中Set底層跟Java一樣嗎?
Redis 幾種常見的數(shù)據(jù)類型底層原理,前面跟小伙伴們已經(jīng)扒了 String 和 List 了,今天我們再來看看 Set。
一、Java 里的 Set
從體驗上來說,Redis 里邊的 Set 有點像 Java 里的 Set,使用感覺差不多也是這個樣子。
都是唯一,都是無序。
不過小伙伴們知道,我們 Java 里邊的 Set,幾種不同類型的 Set 底層都不約而同的指向了 Map。
HashSet
底層使用的是HashMap(實際上是一個專門的 IdentityHashMap),其中元素作為 key,對應的 value 通常是一個固定的對象(例如,PRESENT 對象),以此來實現(xiàn)元素的去重。
HashSet 提供了非常快的插入、刪除和查找操作,平均時間復雜度為 O(1),但不保證元素的順序。
TreeSet
- 底層使用的是 TreeMap,它是一個紅黑樹實現(xiàn)的有序映射。TreeSet 中的元素會被排序,排序依據(jù)可以是自然順序(通過實現(xiàn) Comparable 接口),也可以是用戶提供的 Comparator。
- TreeSet 保證了元素的排序,同時也提供了有序集合的操作,如 headSet(), tailSet(), subSet() 等,時間復雜度通常為O(logn)。
LinkedHashSet
- 底層使用的是 LinkedHashMap,它結合了 HashMap 的快速查找特性和 LinkedHashMap 的有序性。
- LinkedHashSet 維護了元素的插入順序,同時提供了快速的插入、刪除和查找操作。時間復雜度通常為O(1)。
EnumSet
- 專為枚舉類型的元素設計,底層使用位向量(bit vector)來存儲元素,非常適合枚舉類型的集合,提供了非常高效的存儲和操作。
- EnumSet 在枚舉類型元素的數(shù)量較少時非常高效,時間復雜度通常為O(1)。
當然這是 Java 里的,Redis 中和這個并不相同。
二、Redis 的 Set
Redis 中 Set 的底層要分情況來看。
整體上來說有兩種:
- intset
- hashtable
具體使用哪種取決于集合中元素的數(shù)量和類型。
2.1 intset
當集合中的所有元素都是整數(shù),并且集合的大小不超過 512 個元素時,Redis 會使用 intset 數(shù)據(jù)結構來存儲集合。
intset 是一個無序的整數(shù)數(shù)組,它使用緊湊的方式存儲整數(shù)元素,以節(jié)省內(nèi)存。intset 的特點包括:
- 使用緊湊的存儲方式,每個整數(shù)根據(jù)其大小占用最少的字節(jié)數(shù)(1 字節(jié)、2 字節(jié)、4 字節(jié)或 8 字節(jié))。
- 支持快速的插入和刪除操作。
- 不保證元素的順序。
這里的 512 是咋來的呢?這個參數(shù)我們可以在 redis.conf 中進行配置,不配置的話默認是 512:
圖片
來看個簡單的例子。
所有元素都是整數(shù),且元素個數(shù)不超過 512:
圖片
有元素不是整數(shù):
圖片
可以看到,此時就是另外一種 hashtable 類型了。
具體到 intset 內(nèi)部,又分為不同的編碼格式。
- int16:這個是每兩個字節(jié)表示一個整數(shù),兩個字節(jié)就是 16 位,表示的整數(shù)范圍就是 (-2^15)~(2^15-1)
- int32:這個是每四個字節(jié)表示一個整數(shù),四個字節(jié)就是 32 位,表示的整數(shù)范圍就是 (-2^31)~(2^31-1)
- int64:這個是每八個字節(jié)表示一個整數(shù),八個字節(jié)就是 64 位,表示的整數(shù)范圍就是 (-2^63)~(2^63-1)
如果一開始使用的是 int16,后來存儲的數(shù)據(jù)大小超了,那么 Redis 會自動將編碼格式升級為 int32,并且將舊數(shù)據(jù)復制過來。
不過需要注意的是,編碼格式可以從 int16 升級為 int32,但是并不會從 int32 降級為 int16,即使數(shù)據(jù)已經(jīng)變?yōu)?1 了。
2.2 hashtable
當集合中的元素不是整數(shù)或者集合的大小超過了 512 時,Redis 會使用 hashtable(散列表)來存儲集合。hashtable 是一種散列表實現(xiàn),它可以高效地存儲任意類型的數(shù)據(jù),并提供快速的查找操作。hashtable 的特點包括:
- 支持任意類型的數(shù)據(jù)。
- 提供快速的插入、查找和刪除操作。
- 不保證元素的順序。
當集合的元素發(fā)生變化時,Redis 會自動轉換數(shù)據(jù)結構以適應新的需求。例如,如果一個原本使用 intset 的集合添加了非整數(shù)元素,Redis 會將數(shù)據(jù)結構從 intset 轉換為 hashtable。
Redis 如此煞費苦心,其實就一個目的,高效率的使用內(nèi)存。