7.1. Map

Redis based distributed Map object for Java implements ConcurrentMap interface. This object is fully thread-safe. Consider to use Live Object service to store POJO object as Redis Map. Redis uses serialized state to check key uniqueness instead of key’s hashCode()/equals() methods.

It has Async, Reactive and RxJava3 interfaces.

If Map used mostly for read operations and/or network roundtrips are undesirable use Map with Local cache support.

  1. RMap<String, SomeObject> map = redisson.getMap("anyMap");
  2. SomeObject prevObject = map.put("123", new SomeObject());
  3. SomeObject currentObject = map.putIfAbsent("323", new SomeObject());
  4. SomeObject obj = map.remove("123");
  5. // use fast* methods when previous value is not required
  6. map.fastPut("a", new SomeObject());
  7. map.fastPutIfAbsent("d", new SomeObject());
  8. map.fastRemove("b");
  9. RFuture<SomeObject> putAsyncFuture = map.putAsync("321");
  10. RFuture<Void> fastPutAsyncFuture = map.fastPutAsync("321");
  11. map.fastPutAsync("321", new SomeObject());
  12. map.fastRemoveAsync("321");

RMap object allows to bind a Lock/ReadWriteLock/Semaphore/CountDownLatch object per key:

  1. RMap<MyKey, MyValue> map = redisson.getMap("anyMap");
  2. MyKey k = new MyKey();
  3. RLock keyLock = map.getLock(k);
  4. keyLock.lock();
  5. try {
  6. MyValue v = map.get(k);
  7. // process value ...
  8. } finally {
  9. keyLock.unlock();
  10. }
  11. RReadWriteLock rwLock = map.getReadWriteLock(k);
  12. rwLock.readLock().lock();
  13. try {
  14. MyValue v = map.get(k);
  15. // process value ...
  16. } finally {
  17. keyLock.readLock().unlock();
  18. }

7.1.1. Map eviction, local cache and data partitioning

Redisson provides various Map structure implementations with three important features:

local cache - so called near cache used to speed up read operations and avoid network roundtrips. It caches Map entries on Redisson side and executes read operations up to 45x faster in comparison with common implementation. Local cache instances with the same name connected to the same pub/sub channel. This channel is used for exchanging of update/invalidate events between all instances. Local cache store doesn’t use hashCode()/equals() methods of key object, instead it uses hash of serialized state.

data partitioning - although Map object is cluster compatible its content isn’t scaled/partitioned across multiple Redis master nodes in cluster. Data partitioning allows to scale available memory, read/write operations and entry eviction process for individual Map instance in Redis cluster.

lua entry eviction - allows to define time to live or max idle time parameters per map entry. Redis hash structure doesn’t support eviction thus it’s done on Redisson side through a custom scheduled task which removes expired entries using lua script. Eviction task is started once by getMapCache() method execution per unique object name. So even if instance isn’t used and has expired entries it should be get through getMapCache() method to start the eviction process. This leads to extra Redis calls and eviction task per unique map object name.

advanced entry eviction - allows to define time to live parameter per map entry. Doesn’t use an entry eviction task.

native entry eviction - allows to define time to live parameter per map entry. Doesn’t use an entry eviction task. Requires Redis 7.4+.

Below is the list of all available Map implementations:

RedissonClient
method name
Local
cache
Data
partitioning
Entry
eviction
Ultra-fast
read/write
getMap()
open-source version
getMapCache()
open-source version
lua
getMapCacheNative()
open-source version
native
getLocalCachedMap()
open-source version
✔️
getMap()
Redisson PRO version
✔️
getMapCache()
Redisson PRO version
lua ✔️
getMapCacheNative()
Redisson PRO version
native ✔️
getMapCacheV2()
available only in Redisson PRO
advanced ✔️
getLocalCachedMap()
Redisson PRO version
✔️ ✔️
getLocalCachedMapCache()
available only in Redisson PRO
✔️ lua ✔️
getLocalCachedMapCacheV2()
available only in Redisson PRO
✔️ ✔️ advanced ✔️
getClusteredMap()
available only in Redisson PRO
✔️ ✔️
getClusteredLocalCachedMap()
available only in Redisson PRO
✔️ ✔️ ✔️
getClusteredMapCache()
available only in Redisson PRO
✔️ lua ✔️
getClusteredLocalCachedMapCache()
available only in Redisson PRO
✔️ ✔️ lua ✔️

Redisson also provides Spring Cache and JCache implementations.

Eviction

Map object with eviction support implements org.redisson.api.RMapCache interface and extends java.util.concurrent.ConcurrentMap interface. It also has Async, Reactive and RxJava3 interfaces.

Current Redis implementation doesn’t have map entry eviction functionality. Therefore expired entries are cleaned time to time by org.redisson.eviction.EvictionScheduler. It removes 100 expired entries at once. Task launch time tuned automatically and depends on expired entries amount deleted in previous time and varies between 5 second to half an hour. Thus if clean task deletes 100 entries each time it will be executed every 5 seconds (minimum execution delay). But if current expired entries amount is lower than previous one then execution delay will be increased by 1.5 times and decreased otherwise.

It’s recommended to use single instance of RMapCache object with the same name for each Redisson client instance.

Code example:

  1. RMapCache<String, SomeObject> map = redisson.getMapCache("anyMap");
  2. // or
  3. RMapCache<String, SomeObject> map = redisson.getMapCache("anyMap", MapCacheOptions.defaults());
  4. // or
  5. RMapCacheV2<String, SomeObject> map = redisson.getMapCacheV2("anyMap");
  6. // or
  7. RMapCacheV2<String, SomeObject> map = redisson.getMapCacheV2("anyMap", MapOptions.defaults());
  8. // or
  9. RMapCache<String, SomeObject> map = redisson.getLocalCachedMapCache("anyMap", LocalCachedMapOptions.defaults());
  10. // or
  11. RMapCache<String, SomeObject> map = redisson.getClusteredLocalCachedMapCache("anyMap", LocalCachedMapOptions.defaults());
  12. // or
  13. RMapCache<String, SomeObject> map = redisson.getClusteredMapCache("anyMap");
  14. // or
  15. RMapCache<String, SomeObject> map = redisson.getClusteredMapCache("anyMap", MapCacheOptions.defaults());
  16. // ttl = 10 minutes,
  17. map.put("key1", new SomeObject(), 10, TimeUnit.MINUTES);
  18. // ttl = 10 minutes, maxIdleTime = 10 seconds
  19. map.put("key1", new SomeObject(), 10, TimeUnit.MINUTES, 10, TimeUnit.SECONDS);
  20. // ttl = 3 seconds
  21. map.putIfAbsent("key2", new SomeObject(), 3, TimeUnit.SECONDS);
  22. // ttl = 40 seconds, maxIdleTime = 10 seconds
  23. map.putIfAbsent("key2", new SomeObject(), 40, TimeUnit.SECONDS, 10, TimeUnit.SECONDS);
  24. // if object is not used anymore
  25. map.destroy();

Local cache

Map object with local cache support implements org.redisson.api.RLocalCachedMap which extends java.util.concurrent.ConcurrentMap interface. This object is fully thread-safe.

It’s recommended to use single instance of LocalCachedMap instance per name for each Redisson client instance. Same LocalCachedMapOptions object should be used across all instances with the same name.

Follow options could be supplied during object creation:

  1. LocalCachedMapOptions options = LocalCachedMapOptions.defaults()
  2. // Defines whether to store a cache miss into the local cache.
  3. // Default value is false.
  4. .storeCacheMiss(false);
  5. // Defines store mode of cache data.
  6. // Follow options are available:
  7. // LOCALCACHE - store data in local cache only and use Redis only for data update/invalidation.
  8. // LOCALCACHE_REDIS - store data in both Redis and local cache.
  9. .storeMode(StoreMode.LOCALCACHE_REDIS)
  10. // Defines Cache provider used as local cache store.
  11. // Follow options are available:
  12. // REDISSON - uses Redisson own implementation
  13. // CAFFEINE - uses Caffeine implementation
  14. .cacheProvider(CacheProvider.REDISSON)
  15. // Defines local cache eviction policy.
  16. // Follow options are available:
  17. // LFU - Counts how often an item was requested. Those that are used least often are discarded first.
  18. // LRU - Discards the least recently used items first
  19. // SOFT - Uses soft references, entries are removed by GC
  20. // WEAK - Uses weak references, entries are removed by GC
  21. // NONE - No eviction
  22. .evictionPolicy(EvictionPolicy.NONE)
  23. // If cache size is 0 then local cache is unbounded.
  24. .cacheSize(1000)
  25. // Defines strategy for load missed local cache updates after Redis connection failure.
  26. //
  27. // Follow reconnection strategies are available:
  28. // CLEAR - Clear local cache if map instance has been disconnected for a while.
  29. // LOAD - Store invalidated entry hash in invalidation log for 10 minutes
  30. // Cache keys for stored invalidated entry hashes will be removed
  31. // if LocalCachedMap instance has been disconnected less than 10 minutes
  32. // or whole cache will be cleaned otherwise.
  33. // NONE - Default. No reconnection handling
  34. .reconnectionStrategy(ReconnectionStrategy.NONE)
  35. // Defines local cache synchronization strategy.
  36. //
  37. // Follow sync strategies are available:
  38. // INVALIDATE - Default. Invalidate cache entry across all LocalCachedMap instances on map entry change
  39. // UPDATE - Insert/update cache entry across all LocalCachedMap instances on map entry change
  40. // NONE - No synchronizations on map changes
  41. .syncStrategy(SyncStrategy.INVALIDATE)
  42. // time to live for each map entry in local cache
  43. .timeToLive(10000)
  44. // or
  45. .timeToLive(10, TimeUnit.SECONDS)
  46. // max idle time for each map entry in local cache
  47. .maxIdle(10000)
  48. // or
  49. .maxIdle(10, TimeUnit.SECONDS);

Code example:

  1. RLocalCachedMap<String, Integer> map = redisson.getLocalCachedMap("test", LocalCachedMapOptions.defaults());
  2. // or
  3. RLocalCachedMap<String, SomeObject> map = redisson.getLocalCachedMapCache("anyMap", LocalCachedMapCacheOptions.defaults());
  4. // or
  5. RLocalCachedMap<String, SomeObject> map = redisson.getClusteredLocalCachedMapCache("anyMap", LocalCachedMapCacheOptions.defaults());
  6. // or
  7. RLocalCachedMap<String, SomeObject> map = redisson.getClusteredLocalCachedMap("anyMap", LocalCachedMapOptions.defaults());
  8. String prevObject = map.put("123", 1);
  9. String currentObject = map.putIfAbsent("323", 2);
  10. String obj = map.remove("123");
  11. // use fast* methods when previous value is not required
  12. map.fastPut("a", 1);
  13. map.fastPutIfAbsent("d", 32);
  14. map.fastRemove("b");
  15. RFuture<String> putAsyncFuture = map.putAsync("321");
  16. RFuture<Void> fastPutAsyncFuture = map.fastPutAsync("321");
  17. map.fastPutAsync("321", new SomeObject());
  18. map.fastRemoveAsync("321");

Object should be destroyed if it not used anymore, but it’s not necessary to call destroy method if Redisson goes shutdown.

  1. RLocalCachedMap<String, Integer> map = ...
  2. map.destroy();
How to load data to avoid invalidation messages traffic.

Code example:

  1. public void loadData(String cacheName, Map<String, String> data) {
  2. RLocalCachedMap<String, String> clearMap = redisson.getLocalCachedMap(cacheName,
  3. LocalCachedMapOptions.defaults().cacheSize(1).syncStrategy(SyncStrategy.INVALIDATE));
  4. RLocalCachedMap<String, String> loadMap = redisson.getLocalCachedMap(cacheName,
  5. LocalCachedMapOptions.defaults().cacheSize(1).syncStrategy(SyncStrategy.NONE));
  6. loadMap.putAll(data);
  7. clearMap.clearLocalCache();
  8. }

Data partitioning

Map object with data partitioning support implements org.redisson.api.RClusteredMap which extends java.util.concurrent.ConcurrentMap interface. Read more details about data partitioning here).

Code example:

  1. RClusteredMap<String, SomeObject> map = redisson.getClusteredMap("anyMap");
  2. // or
  3. RClusteredMap<String, SomeObject> map = redisson.getClusteredLocalCachedMapCache("anyMap", LocalCachedMapCacheOptions.defaults());
  4. // or
  5. RClusteredMap<String, SomeObject> map = redisson.getClusteredLocalCachedMap("anyMap", LocalCachedMapOptions.defaults());
  6. // or
  7. RClusteredMap<String, SomeObject> map = redisson.getClusteredMapCache("anyMap");
  8. SomeObject prevObject = map.put("123", new SomeObject());
  9. SomeObject currentObject = map.putIfAbsent("323", new SomeObject());
  10. SomeObject obj = map.remove("123");
  11. map.fastPut("321", new SomeObject());
  12. map.fastRemove("321");

7.1.2. Map persistence

Redisson allows to store Map data in external storage along with Redis store.
Use cases:

  1. Redisson Map object as a cache between an application and external storage.
  2. Increase durability of Redisson Map data and life-span of evicted entries.
  3. Caching for databases, web services or any other data source.
Read-through strategy

If requested entry doesn’t exist in the Redisson Map object when it will be loaded using provided MapLoader object. Code example:

  1. MapLoader<String, String> mapLoader = new MapLoader<String, String>() {
  2. @Override
  3. public Iterable<String> loadAllKeys() {
  4. List<String> list = new ArrayList<String>();
  5. Statement statement = conn.createStatement();
  6. try {
  7. ResultSet result = statement.executeQuery("SELECT id FROM student");
  8. while (result.next()) {
  9. list.add(result.getString(1));
  10. }
  11. } finally {
  12. statement.close();
  13. }
  14. return list;
  15. }
  16. @Override
  17. public String load(String key) {
  18. PreparedStatement preparedStatement = conn.prepareStatement("SELECT name FROM student where id = ?");
  19. try {
  20. preparedStatement.setString(1, key);
  21. ResultSet result = preparedStatement.executeQuery();
  22. if (result.next()) {
  23. return result.getString(1);
  24. }
  25. return null;
  26. } finally {
  27. preparedStatement.close();
  28. }
  29. }
  30. };

Configuration example:

  1. MapOptions<K, V> options = MapOptions.<K, V>defaults()
  2. .loader(mapLoader);
  3. MapCacheOptions<K, V> mcoptions = MapCacheOptions.<K, V>defaults()
  4. .loader(mapLoader);
  5. RMap<K, V> map = redisson.getMap("test", options);
  6. // or
  7. RMapCache<K, V> map = redisson.getMapCache("test", mcoptions);
  8. // or with performance boost up to 45x times
  9. RLocalCachedMap<K, V> map = redisson.getLocalCachedMap("test", options);
  10. // or with performance boost up to 45x times
  11. RLocalCachedMapCache<K, V> map = redisson.getLocalCachedMapCache("test", mcoptions);
Write-through (synchronous) strategy

When the Map entry is being updated method won’t return until Redisson update it in an external storage using MapWriter object. Code example:

  1. MapWriter<String, String> mapWriter = new MapWriter<String, String>() {
  2. @Override
  3. public void write(Map<String, String> map) {
  4. PreparedStatement preparedStatement = conn.prepareStatement("INSERT INTO student (id, name) values (?, ?)");
  5. try {
  6. for (Entry<String, String> entry : map.entrySet()) {
  7. preparedStatement.setString(1, entry.getKey());
  8. preparedStatement.setString(2, entry.getValue());
  9. preparedStatement.addBatch();
  10. }
  11. preparedStatement.executeBatch();
  12. } finally {
  13. preparedStatement.close();
  14. }
  15. }
  16. @Override
  17. public void delete(Collection<String> keys) {
  18. PreparedStatement preparedStatement = conn.prepareStatement("DELETE FROM student where id = ?");
  19. try {
  20. for (String key : keys) {
  21. preparedStatement.setString(1, key);
  22. preparedStatement.addBatch();
  23. }
  24. preparedStatement.executeBatch();
  25. } finally {
  26. preparedStatement.close();
  27. }
  28. }
  29. };

Configuration example:

  1. MapOptions<K, V> options = MapOptions.<K, V>defaults()
  2. .writer(mapWriter)
  3. .writeMode(WriteMode.WRITE_THROUGH);
  4. MapCacheOptions<K, V> mcoptions = MapCacheOptions.<K, V>defaults()
  5. .writer(mapWriter)
  6. .writeMode(WriteMode.WRITE_THROUGH);
  7. RMap<K, V> map = redisson.getMap("test", options);
  8. // or
  9. RMapCache<K, V> map = redisson.getMapCache("test", mcoptions);
  10. // or with performance boost up to 45x times
  11. RLocalCachedMap<K, V> map = redisson.getLocalCachedMap("test", options);
  12. // or with performance boost up to 45x times
  13. RLocalCachedMapCache<K, V> map = redisson.getLocalCachedMapCache("test", mcoptions);
Write-behind (asynchronous) strategy

Updates of Map object are accumulated in batches and asynchronously written with defined delay to external storage through MapWriter object.
writeBehindDelay - delay of batched write or delete operation. Default value is 1000 milliseconds. writeBehindBatchSize - size of batch. Each batch contains Map Entry write or delete commands. Default value is 50.

Configuration example:
  1. MapOptions<K, V> options = MapOptions.<K, V>defaults()
  2. .writer(mapWriter)
  3. .writeMode(WriteMode.WRITE_BEHIND)
  4. .writeBehindDelay(5000)
  5. .writeBehindBatchSize(100);
  6. MapCacheOptions<K, V> mcoptions = MapCacheOptions.<K, V>defaults()
  7. .writer(mapWriter)
  8. .writeMode(WriteMode.WRITE_BEHIND)
  9. .writeBehindDelay(5000)
  10. .writeBehindBatchSize(100);
  11. RMap<K, V> map = redisson.getMap("test", options);
  12. // or
  13. RMapCache<K, V> map = redisson.getMapCache("test", mcoptions);
  14. // or with performance boost up to 45x times
  15. RLocalCachedMap<K, V> map = redisson.getLocalCachedMap("test", options);
  16. // or with performance boost up to 45x times
  17. RLocalCachedMapCache<K, V> map = redisson.getLocalCachedMapCache("test", mcoptions);

This feature available for RMap, RMapCache, RLocalCachedMap and RLocalCachedMapCache objects.

Usage of RLocalCachedMap and RLocalCachedMapCache objects boost Redis read-operations up to 45x times and give almost instant speed for database, web service or any other data source.

7.1.3. Map listeners

Redisson allows to bind listeners per RMap object.

RMap object allows to track follow events over the data.

Listener class name Event description
org.redisson.api.listener.TrackingListener Entry created/removed/updated after read operation
org.redisson.api.listener.MapPutListener Entry created/updated
org.redisson.api.listener.MapRemoveListener Entry removed
org.redisson.api.ExpiredObjectListener RMap object expired
org.redisson.api.DeletedObjectListener RMap object deleted

Usage examples:

  1. RMap<String, SomeObject> map = redisson.getMap("anyMap");
  2. int listenerId = map.addListener(new DeletedObjectListener() {
  3. @Override
  4. public void onDeleted(String name) {
  5. // ...
  6. }
  7. });
  8. int listenerId = map.addListener(new ExpiredObjectListener() {
  9. @Override
  10. public void onExpired(String name) {
  11. // ...
  12. }
  13. });
  14. int listenerId = map.addListener(new MapPutListener() {
  15. @Override
  16. public void onPut(String name) {
  17. // ...
  18. }
  19. });
  20. int listenerId = map.addListener(new MapRemoveListener() {
  21. @Override
  22. public void onRemove(String name) {
  23. // ...
  24. }
  25. });
  26. map.removeListener(listenerId);

RMapCache object allows to track additional events over the data.

Listener class name Event description
org.redisson.api.map.event.EntryCreatedListener Entry created
org.redisson.api.map.event.EntryExpiredListener Entry expired
org.redisson.api.map.event.EntryRemovedListener Entry removed
org.redisson.api.map.event.EntryUpdatedListener Entry updated

Usage examples:

  1. RMapCache<String, SomeObject> map = redisson.getMapCache("anyMap");
  2. // or
  3. RMapCache<String, SomeObject> map = redisson.getLocalCachedMapCache(LocalCachedMapCacheOptions.name("anyMap"));
  4. // or
  5. RMapCache<String, SomeObject> map = redisson.getClusteredLocalCachedMapCache("anyMap", LocalCachedMapOptions.defaults());
  6. // or
  7. RMapCache<String, SomeObject> map = redisson.getClusteredMapCache("anyMap");
  8. int listenerId = map.addListener(new EntryUpdatedListener<Integer, Integer>() {
  9. @Override
  10. public void onUpdated(EntryEvent<Integer, Integer> event) {
  11. event.getKey(); // key
  12. event.getValue() // new value
  13. event.getOldValue() // old value
  14. // ...
  15. }
  16. });
  17. int listenerId = map.addListener(new EntryCreatedListener<Integer, Integer>() {
  18. @Override
  19. public void onCreated(EntryEvent<Integer, Integer> event) {
  20. event.getKey(); // key
  21. event.getValue() // value
  22. // ...
  23. }
  24. });
  25. int listenerId = map.addListener(new EntryExpiredListener<Integer, Integer>() {
  26. @Override
  27. public void onExpired(EntryEvent<Integer, Integer> event) {
  28. event.getKey(); // key
  29. event.getValue() // value
  30. // ...
  31. }
  32. });
  33. int listenerId = map.addListener(new EntryRemovedListener<Integer, Integer>() {
  34. @Override
  35. public void onRemoved(EntryEvent<Integer, Integer> event) {
  36. event.getKey(); // key
  37. event.getValue() // value
  38. // ...
  39. }
  40. });
  41. map.removeListener(listenerId);

7.1.4. LRU/LFU bounded Map

Map object which implements RMapCache interface could be bounded using Least Recently Used (LRU) or Least Frequently Used (LFU) order. Bounded Map allows to store map entries within defined limit and retire entries in defined order.

Use cases: limited Redis memory.

  1. RMapCache<String, SomeObject> map = redisson.getMapCache("anyMap");
  2. // or
  3. RMapCache<String, SomeObject> map = redisson.getMapCache("anyMap", MapCacheOptions.defaults());
  4. // or
  5. RMapCache<String, SomeObject> map = redisson.getLocalCachedMapCache("anyMap", LocalCachedMapOptions.defaults());
  6. // or
  7. RMapCache<String, SomeObject> map = redisson.getClusteredLocalCachedMapCache("anyMap", LocalCachedMapOptions.defaults());
  8. // or
  9. RMapCache<String, SomeObject> map = redisson.getClusteredMapCache("anyMap");
  10. // or
  11. RMapCache<String, SomeObject> map = redisson.getClusteredMapCache("anyMap", MapCacheOptions.defaults());
  12. // tries to set limit map to 10 entries using LRU eviction algorithm
  13. map.trySetMaxSize(10);
  14. // ... using LFU eviction algorithm
  15. map.trySetMaxSize(10, EvictionMode.LFU);
  16. // set or change limit map to 10 entries using LRU eviction algorithm
  17. map.setMaxSize(10);
  18. // ... using LFU eviction algorithm
  19. map.setMaxSize(10, EvictionMode.LFU);
  20. map.put("1", "2");
  21. map.put("3", "3", 1, TimeUnit.SECONDS);

7.2. Multimap

Redis based Multimap for Java allows to bind multiple values per key. This object is fully thread-safe. Keys amount limited by Redis to 4 294 967 295 elements. Redis uses serialized state to check key uniqueness instead of key’s hashCode()/equals() methods.

It has Async, Reactive and RxJava3 interfaces.

7.2.1. Set based Multimap

Set based Multimap doesn’t allow duplications for values per key.

  1. RSetMultimap<SimpleKey, SimpleValue> map = redisson.getSetMultimap("myMultimap");
  2. map.put(new SimpleKey("0"), new SimpleValue("1"));
  3. map.put(new SimpleKey("0"), new SimpleValue("2"));
  4. map.put(new SimpleKey("3"), new SimpleValue("4"));
  5. Set<SimpleValue> allValues = map.get(new SimpleKey("0"));
  6. List<SimpleValue> newValues = Arrays.asList(new SimpleValue("7"), new SimpleValue("6"), new SimpleValue("5"));
  7. Set<SimpleValue> oldValues = map.replaceValues(new SimpleKey("0"), newValues);
  8. Set<SimpleValue> removedValues = map.removeAll(new SimpleKey("0"));

7.2.2. List based Multimap

List based Multimap object for Java stores entries in insertion order and allows duplicates for values mapped to key.

  1. RListMultimap<SimpleKey, SimpleValue> map = redisson.getListMultimap("test1");
  2. map.put(new SimpleKey("0"), new SimpleValue("1"));
  3. map.put(new SimpleKey("0"), new SimpleValue("2"));
  4. map.put(new SimpleKey("0"), new SimpleValue("1"));
  5. map.put(new SimpleKey("3"), new SimpleValue("4"));
  6. List<SimpleValue> allValues = map.get(new SimpleKey("0"));
  7. Collection<SimpleValue> newValues = Arrays.asList(new SimpleValue("7"), new SimpleValue("6"), new SimpleValue("5"));
  8. List<SimpleValue> oldValues = map.replaceValues(new SimpleKey("0"), newValues);
  9. List<SimpleValue> removedValues = map.removeAll(new SimpleKey("0"));

7.2.3. Multimap eviction

Multimap object for Java with eviction support implemented by separated MultimapCache object. There are RSetMultimapCache and RListMultimapCache objects for Set and List Multimaps respectivly.

Expired entries are cleaned by org.redisson.EvictionScheduler. It removes 100 expired entries at once. Task launch time tuned automatically and depends on expired entries amount deleted in previous time and varies between 1 second to 2 hours. Thus if clean task deletes 100 entries each time it will be executed every second (minimum execution delay). But if current expired entries amount is lower than previous one then execution delay will be increased by 1.5 times.

RSetMultimapCache example:

  1. RSetMultimapCache<String, String> multimap = redisson.getSetMultimapCache("myMultimap");
  2. multimap.put("1", "a");
  3. multimap.put("1", "b");
  4. multimap.put("1", "c");
  5. multimap.put("2", "e");
  6. multimap.put("2", "f");
  7. multimap.expireKey("2", 10, TimeUnit.MINUTES);

7.3. Set

Redis based Set object for Java implements java.util.Set interface. This object is fully thread-safe. Keeps elements uniqueness via element state comparison. Set size limited by Redis to 4 294 967 295 elements. Redis uses serialized state to check value uniqueness instead of value’s hashCode()/equals() methods.

It has Async, Reactive and RxJava3 interfaces.

  1. RSet<SomeObject> set = redisson.getSet("anySet");
  2. set.add(new SomeObject());
  3. set.remove(new SomeObject());

RSet object allows to bind a Lock/ReadWriteLock/Semaphore/CountDownLatch object per value:

  1. RSet<MyObject> set = redisson.getSet("anySet");
  2. MyObject value = new MyObject();
  3. RLock lock = map.getLock(value);
  4. lock.lock();
  5. try {
  6. // process value ...
  7. } finally {
  8. lock.unlock();
  9. }

7.3.1. Set eviction and data partitioning

Redisson provides various Set structure implementations with two important features:

data partitioning - although Set object is cluster compatible its content isn’t scaled/partitioned across multiple Redis master nodes in cluster. Data partitioning allows to scale available memory, read/write operations and entry eviction process for individual Set instance in Redis cluster.

entry eviction - allows to define time to live per set value. Redis set structure doesn’t support eviction thus it’s done on Redisson side through custom scheduled task which removes expired entries. Eviction task is started once by getSetCache() method execution per unique object name. If object instance isn’t used and has expired elements it should be get through getSetCache() method to start the eviction process. This leads to extra Redis calls and eviction task per unique set object name.

advanced entry eviction - improved version of the entry eviction process. Doesn’t use an entry eviction task.

Below is the list of all available Map implementations:

RedissonClient
method name
Data
partitioning
Entry
eviction
Advanced
entry eviction
Ultra-fast
read/write
getSet()
open-source version
getSetCache()
open-source version
✔️
getSet()
Redisson PRO version
✔️
getSetCache()
Redisson PRO version
✔️ ✔️
getSetCacheV2()
available only in Redisson PRO
✔️ ✔️ ✔️
getClusteredSet()
available only in Redisson PRO
✔️ ✔️
getClusteredSetCache()
available only in Redisson PRO
✔️ ✔️ ✔️

Eviction

Map object with eviction support implements org.redisson.api.RSetCache which extends java.util.Set interface. It has Async, Reactive and RxJava3 interfaces.

Current Redis implementation doesn’t have set value eviction functionality. Therefore expired entries are cleaned by org.redisson.eviction.EvictionScheduler. It removes 300 expired entries at once. Task launch time tuned automatically and depends on expired entries amount deleted in previous time and varies between 1 second to 1 hour. Thus if clean task deletes 300 entries each time it will be executed every second (minimum execution delay). But if current expired values amount is lower than previous one then execution delay will be increased by 1.5 times.

Code example:

  1. RSetCache<SomeObject> set = redisson.getSetCache("mySet");
  2. // or
  3. RMapCache<SomeObject> set = redisson.getClusteredSetCache("mySet");
  4. // ttl = 10 minutes,
  5. set.add(new SomeObject(), 10, TimeUnit.MINUTES);
  6. // if object is not used anymore
  7. map.destroy();

Data partitioning

Map object with data partitioning support implements org.redisson.api.RClusteredSet which extends java.util.Set interface. Read more details about data partitioning here).

Code example:

  1. RClusteredSet<SomeObject> set = redisson.getClusteredSet("mySet");
  2. // or
  3. RClusteredSet<SomeObject> set = redisson.getClusteredSetCache("mySet");
  4. // ttl = 10 minutes,
  5. map.add(new SomeObject(), 10, TimeUnit.MINUTES);

7.3.2. Set listeners

Redisson allows to bind listeners per RSet object.

Listener class name Event description
org.redisson.api.listener.TrackingListener Element added/removed/updated after read operation
org.redisson.api.ExpiredObjectListener RSet object expired
org.redisson.api.DeletedObjectListener RSet object deleted
org.redisson.api.listener.SetAddListener Element added
org.redisson.api.listener.SetRemoveListener Element removed
org.redisson.api.listener.SetRemoveRandomListener Element randomly removed

Usage example:

  1. RSet<String> set = redisson.getSet("anySet");
  2. int listenerId = set.addListener(new DeletedObjectListener() {
  3. @Override
  4. public void onDeleted(String name) {
  5. // ...
  6. }
  7. });
  8. // ...
  9. set.removeListener(listenerId);

7.4. SortedSet

Redis based distributed SortedSet for Java implements java.util.SortedSet interface. This object is fully thread-safe. It uses comparator to sort elements and keep uniqueness. For String data type it’s recommended to use LexSortedSet object due to performance gain.

  1. RSortedSet<Integer> set = redisson.getSortedSet("anySet");
  2. set.trySetComparator(new MyComparator()); // set object comparator
  3. set.add(3);
  4. set.add(1);
  5. set.add(2);
  6. set.removeAsync(0);
  7. set.addAsync(5);

7.5. ScoredSortedSet

Redis based distributed ScoredSortedSet object. Sorts elements by score defined during element insertion. Keeps elements uniqueness via element state comparison.

It has Async, Reactive and RxJava3 interfaces. Set size is limited by Redis to 4 294 967 295 elements.

  1. RScoredSortedSet<SomeObject> set = redisson.getScoredSortedSet("simple");
  2. set.add(0.13, new SomeObject(a, b));
  3. set.addAsync(0.251, new SomeObject(c, d));
  4. set.add(0.302, new SomeObject(g, d));
  5. set.pollFirst();
  6. set.pollLast();
  7. int index = set.rank(new SomeObject(g, d)); // get element index
  8. Double score = set.getScore(new SomeObject(g, d)); // get element score

7.5.1. ScoredSortedSet data partitioning

Although ‘RScoredSortedSet’ object is cluster compatible its content isn’t scaled across multiple Redis master nodes. RScoredSortedSet data partitioning available only in cluster mode and implemented by separate RClusteredScoredSortedSet object. Size is limited by whole Redis Cluster memory. More about partitioning here).

Below is the list of all available RScoredSortedSet implementations:

RedissonClient
method name
Data partitioning
support
Ultra-fast read/write
getScoredSortedSet()
open-source version
getScoredSortedSet()
Redisson PRO version
✔️
getClusteredScoredSortedSet()
available only in Redisson PRO
✔️ ✔️

Code example:

  1. RClusteredScoredSortedSet set = redisson.getClusteredScoredSortedSet("simpleBitset");
  2. set.add(1.1, "v1");
  3. set.add(1.2, "v2");
  4. set.add(1.3, "v3");
  5. ScoredEntry<String> s = set.firstEntry();
  6. ScoredEntry<String> e = set.pollFirstEntry();

7.5.2. ScoredSortedSet listeners

Redisson allows to bind listeners per RScoredSortedSet object.

Listener class name Event description
org.redisson.api.listener.TrackingListener Element created/removed/updated after read operation
org.redisson.api.listener.ScoredSortedSetAddListener Element created/updated
org.redisson.api.listener.ScoredSortedSetRemoveListener Element removed
org.redisson.api.ExpiredObjectListener RScoredSortedSet object expired
org.redisson.api.DeletedObjectListener RScoredSortedSet object deleted

Usage example:

  1. RScoredSortedSet<String> set = redisson.getScoredSortedSet("anySet");
  2. int listenerId = set.addListener(new DeletedObjectListener() {
  3. @Override
  4. public void onDeleted(String name) {
  5. // ...
  6. }
  7. });
  8. // ...
  9. set.removeListener(listenerId);

7.6. LexSortedSet

Redis based distributed Set object for Java allows String objects only and implements java.util.Set<String> interface. It keeps elements in lexicographical order and maintain elements uniqueness via element state comparison.

It has Async, Reactive and RxJava3 interfaces.

  1. RLexSortedSet set = redisson.getLexSortedSet("simple");
  2. set.add("d");
  3. set.addAsync("e");
  4. set.add("f");
  5. set.rangeTail("d", false);
  6. set.countHead("e");
  7. set.range("d", true, "z", false);

7.6.1. LexSortedSet listeners

Redisson allows to bind listeners per RLexSortedSet object.

Listener class name Event description
org.redisson.api.listener.TrackingListener Element created/removed/updated after read operation
org.redisson.api.listener.ScoredSortedSetAddListener Element created/updated
org.redisson.api.listener.ScoredSortedSetRemoveListener Element removed
org.redisson.api.ExpiredObjectListener RScoredSortedSet object expired
org.redisson.api.DeletedObjectListener RScoredSortedSet object deleted

Usage example:

  1. RLexSortedSet<String> set = redisson.getLexSortedSet("anySet");
  2. int listenerId = set.addListener(new DeletedObjectListener() {
  3. @Override
  4. public void onDeleted(String name) {
  5. // ...
  6. }
  7. });
  8. // ...
  9. set.removeListener(listenerId);

7.7. List

Redis based distributed List object for Java implements java.util.List interface. It keeps elements in insertion order.

It has Async, Reactive and RxJava3 interfaces. List size is limited by Redis to 4 294 967 295 elements.

  1. RList<SomeObject> list = redisson.getList("anyList");
  2. list.add(new SomeObject());
  3. list.get(0);
  4. list.remove(new SomeObject());

7.7.1. List listeners

Redisson allows to bind listeners per RList object.

Listener class name Event description
org.redisson.api.listener.TrackingListener Element created/removed/updated after read operation
org.redisson.api.listener.ListAddListener Element created
org.redisson.api.listener.ListInsertListener Element inserted
org.redisson.api.listener.ListSetListener Element set/updated
org.redisson.api.listener.ListRemoveListener Element removed
org.redisson.api.listener.ListTrimListener List trimmed
org.redisson.api.ExpiredObjectListener RList object expired
org.redisson.api.DeletedObjectListener RList object deleted

Usage example:

  1. RList<String> list = redisson.getList("anyList");
  2. int listenerId = list.addListener(new DeletedObjectListener() {
  3. @Override
  4. public void onDeleted(String name) {
  5. // ...
  6. }
  7. });
  8. // ...
  9. list.removeListener(listenerId);

7.8. Queue

Redis based distributed unbounded Queue object for Java implements java.util.Queue interface. This object is fully thread-safe.

It has Async, Reactive and RxJava3 interfaces.

  1. RQueue<SomeObject> queue = redisson.getQueue("anyQueue");
  2. queue.add(new SomeObject());
  3. SomeObject obj = queue.peek();
  4. SomeObject someObj = queue.poll();

7.8.1. Queue listeners

Redisson allows to bind listeners per RQueue object.

Listener class name Event description
org.redisson.api.listener.TrackingListener Element created/removed/updated after read operation
org.redisson.api.listener.ListAddListener Element created
org.redisson.api.listener.ListRemoveListener Element removed
org.redisson.api.ExpiredObjectListener RQueue object expired
org.redisson.api.DeletedObjectListener RQueue object deleted

Usage example:

  1. RQueue<String> queue = redisson.getQueue("anyList");
  2. int listenerId = queue.addListener(new DeletedObjectListener() {
  3. @Override
  4. public void onDeleted(String name) {
  5. // ...
  6. }
  7. });
  8. // ...
  9. queue.removeListener(listenerId);

7.9. Deque

Redis based distributed unbounded Deque object for Java implements java.util.Deque interface. This object is fully thread-safe.

It has Async, Reactive and RxJava3 interfaces.

  1. RDeque<SomeObject> queue = redisson.getDeque("anyDeque");
  2. queue.addFirst(new SomeObject());
  3. queue.addLast(new SomeObject());
  4. SomeObject obj = queue.removeFirst();
  5. SomeObject someObj = queue.removeLast();

7.9.1. Deque listeners

Redisson allows to bind listeners per RDeque object.

Listener class name Event description
org.redisson.api.listener.TrackingListener Element created/removed/updated after read operation
org.redisson.api.listener.ListAddListener Element created
org.redisson.api.listener.ListRemoveListener Element removed
org.redisson.api.ExpiredObjectListener RDeque object expired
org.redisson.api.DeletedObjectListener RDeque object deleted

Usage example:

  1. RDeque<String> deque = redisson.getDeque("anyList");
  2. int listenerId = deque.addListener(new DeletedObjectListener() {
  3. @Override
  4. public void onDeleted(String name) {
  5. // ...
  6. }
  7. });
  8. // ...
  9. deque.removeListener(listenerId);

7.10. Blocking Queue

Redis based distributed unbounded BlockingQueue object for Java implements java.util.concurrent.BlockingQueue interface. This object is fully thread-safe.

It has Async, Reactive and RxJava3 interfaces.

  1. RBlockingQueue<SomeObject> queue = redisson.getBlockingQueue("anyQueue");
  2. queue.offer(new SomeObject());
  3. SomeObject obj = queue.peek();
  4. SomeObject obj = queue.poll();
  5. SomeObject obj = queue.poll(10, TimeUnit.MINUTES);

poll, pollFromAny, pollLastAndOfferFirstTo and take methods are resubscribed automatically during re-connection to Redis server or failover.

7.11. Bounded Blocking Queue

Redis based distributed BoundedBlockingQueue for Java implements java.util.concurrent.BlockingQueue interface. BoundedBlockingQueue size limited by Redis to 4 294 967 295 elements. This object is fully thread-safe. This object is fully thread-safe.

Queue capacity should be defined once by trySetCapacity() method before the usage:

  1. RBoundedBlockingQueue<SomeObject> queue = redisson.getBoundedBlockingQueue("anyQueue");
  2. // returns `true` if capacity set successfully and `false` if it already set.
  3. queue.trySetCapacity(2);
  4. queue.offer(new SomeObject(1));
  5. queue.offer(new SomeObject(2));
  6. // will be blocked until free space available in queue
  7. queue.put(new SomeObject());
  8. SomeObject obj = queue.peek();
  9. SomeObject someObj = queue.poll();
  10. SomeObject ob = queue.poll(10, TimeUnit.MINUTES);

poll, pollFromAny, pollLastAndOfferFirstTo and take methods will be resubscribed automatically during reconnection to Redis server or Redis server failover.

7.12. Blocking Deque

Java implementation of Redis based BlockingDeque implements java.util.concurrent.BlockingDeque interface. This object is fully thread-safe. This object is fully thread-safe.

It has Async, Reactive and RxJava3 interfaces.

  1. RBlockingDeque<Integer> deque = redisson.getBlockingDeque("anyDeque");
  2. deque.putFirst(1);
  3. deque.putLast(2);
  4. Integer firstValue = queue.takeFirst();
  5. Integer lastValue = queue.takeLast();
  6. Integer firstValue = queue.pollFirst(10, TimeUnit.MINUTES);
  7. Integer lastValue = queue.pollLast(3, TimeUnit.MINUTES);

poll, pollFromAny, pollLastAndOfferFirstTo and take methods are resubscribed automatically during re-connection to Redis server or failover.

7.13. Blocking Fair Queue

Redis based distributed BlockingFairQueue for Java implements java.util.concurrent.BlockingQueue interface. This object is fully thread-safe.

When queue consumers in different parts of network: some of them closer to redis and some further. “further” consumers will get lower amount of messages from queue due to network delays. In turn “closer” consumers will get higher amount and this could lead to client overloading.

Blocking queue with fair polling guarantees access order for poll and take methods and allows to get uniformly distributed consumption.

  1. RBlockingFairQueue queue = redisson.getBlockingFairQueue("myQueue");
  2. queue.offer(new SomeObject());
  3. SomeObject element = queue.peek();
  4. SomeObject element = queue.poll();
  5. SomeObject element = queue.poll(10, TimeUnit.MINUTES);
  6. SomeObject element = queue.take();

This feature available only in Redisson PRO edition.

7.14. Blocking Fair Deque

Redis based distributed BlockingFairDeque for Java implements java.util.concurrent.BlockingDeque interface. This object is fully thread-safe.

When deque consumers in different parts of network: some of them closer to redis and some further. “further” consumers will get lower amount of messages from queue due to network delays. In turn “closer” consumers will get higher amount and this could lead to client overloading.

Blocking deque with fair polling guarantees access order for poll, take, pollFirst, takeFirst, pollLast and takeLast methods and allows to get uniformly distributed consumption.

  1. RBlockingFairDeque deque = redisson.getBlockingFairDeque("myDeque");
  2. deque.offer(new SomeObject());
  3. SomeObject firstElement = queue.peekFirst();
  4. SomeObject firstElement = queue.pollFirst();
  5. SomeObject firstElement = queue.pollFirst(10, TimeUnit.MINUTES);
  6. SomeObject firstElement = queue.takeFirst();
  7. SomeObject lastElement = queue.peekLast();
  8. SomeObject lastElement = queue.pollLast();
  9. SomeObject lastElement = queue.pollLast(10, TimeUnit.MINUTES);
  10. SomeObject lastElement = queue.takeLast();

This feature available only in Redisson PRO edition.

7.15. Delayed Queue

Redis based DelayedQueue object for Java allows to transfer each element to destination queue with specified delay. Destination queue could be any queue implemented RQueue interface. This object is fully thread-safe.

Could be useful for exponential backoff strategy used for message delivery to consumer. If application is restarted, an instance of delayed queue should created in order for the pending items to be added to the destination queue.

  1. RBlockingQueue<String> distinationQueue = ...
  2. RDelayedQueue<String> delayedQueue = getDelayedQueue(distinationQueue);
  3. // move object to distinationQueue in 10 seconds
  4. delayedQueue.offer("msg1", 10, TimeUnit.SECONDS);
  5. // move object to distinationQueue in 1 minutes
  6. delayedQueue.offer("msg2", 1, TimeUnit.MINUTES);
  7. // msg1 will appear in 10 seconds
  8. distinationQueue.poll(15, TimeUnit.SECONDS);
  9. // msg2 will appear in 2 seconds
  10. distinationQueue.poll(2, TimeUnit.SECONDS);

Object should be destroyed if it not used anymore, but it’s not necessary to call destroy method if Redisson goes shutdown.

  1. RDelayedQueue<String> delayedQueue = ...
  2. delayedQueue.destroy();

7.16. Priority Queue

Java implementation of Redis based PriorityQueue implements java.util.Queue interface. Elements are ordered according to natural order of java.lang.Comparable interface or defined java.util.Comparator. This object is fully thread-safe.

Use trySetComparator() method to define own java.util.Comparator.

Code example:

  1. public class Entry implements Comparable<Entry>, Serializable {
  2. private String key;
  3. private Integer value;
  4. public Entry(String key, Integer value) {
  5. this.key = key;
  6. this.value = value;
  7. }
  8. @Override
  9. public int compareTo(Entry o) {
  10. return key.compareTo(o.key);
  11. }
  12. }
  13. RPriorityQueue<Entry> queue = redisson.getPriorityQueue("anyQueue");
  14. queue.add(new Entry("b", 1));
  15. queue.add(new Entry("c", 1));
  16. queue.add(new Entry("a", 1));
  17. // Entry [a:1]
  18. Entry e = queue.poll();
  19. // Entry [b:1]
  20. Entry e = queue.poll();
  21. // Entry [c:1]
  22. Entry e = queue.poll();

7.17. Priority Deque

Java implementation of Redis based PriorityDeque implements java.util.Deque interface. Elements are ordered according to natural order of java.lang.Comparable interface or defined java.util.Comparator. This object is fully thread-safe.

Use trySetComparator() method to define own java.util.Comparator.

Code example:

  1. public class Entry implements Comparable<Entry>, Serializable {
  2. private String key;
  3. private Integer value;
  4. public Entry(String key, Integer value) {
  5. this.key = key;
  6. this.value = value;
  7. }
  8. @Override
  9. public int compareTo(Entry o) {
  10. return key.compareTo(o.key);
  11. }
  12. }
  13. RPriorityDeque<Entry> queue = redisson.getPriorityDeque("anyQueue");
  14. queue.add(new Entry("b", 1));
  15. queue.add(new Entry("c", 1));
  16. queue.add(new Entry("a", 1));
  17. // Entry [a:1]
  18. Entry e = queue.pollFirst();
  19. // Entry [c:1]
  20. Entry e = queue.pollLast();

7.18. Priority Blocking Queue

Java implementation of Redis based PriorityBlockingQueue similar to JDK java.util.concurrent.PriorityBlockingQueue object. Elements are ordered according to natural order of java.lang.Comparable interface or defined java.util.Comparator. This object is fully thread-safe.

Use trySetComparator() method to define own java.util.Comparator.

poll, pollLastAndOfferFirstTo and take methods are resubscribed automatically during re-connection to Redis server or failover.

Code example:

  1. public class Entry implements Comparable<Entry>, Serializable {
  2. private String key;
  3. private Integer value;
  4. public Entry(String key, Integer value) {
  5. this.key = key;
  6. this.value = value;
  7. }
  8. @Override
  9. public int compareTo(Entry o) {
  10. return key.compareTo(o.key);
  11. }
  12. }
  13. RPriorityBlockingQueue<Entry> queue = redisson.getPriorityBlockingQueue("anyQueue");
  14. queue.add(new Entry("b", 1));
  15. queue.add(new Entry("c", 1));
  16. queue.add(new Entry("a", 1));
  17. // Entry [a:1]
  18. Entry e = queue.take();

7.19. Priority Blocking Deque

Java implementation of Redis based PriorityBlockingDeque implements java.util.concurrent.BlockingDeque interface. Elements are ordered according to natural order of java.lang.Comparable interface or defined java.util.Comparator. This object is fully thread-safe.

Use trySetComparator() method to define own java.util.Comparator.

poll, pollLastAndOfferFirstTo, take methods are resubscribed automatically during re-connection to Redis server or failover.

Code example:

  1. public class Entry implements Comparable<Entry>, Serializable {
  2. private String key;
  3. private Integer value;
  4. public Entry(String key, Integer value) {
  5. this.key = key;
  6. this.value = value;
  7. }
  8. @Override
  9. public int compareTo(Entry o) {
  10. return key.compareTo(o.key);
  11. }
  12. }
  13. RPriorityBlockingDeque<Entry> queue = redisson.getPriorityBlockingDeque("anyQueue");
  14. queue.add(new Entry("b", 1));
  15. queue.add(new Entry("c", 1));
  16. queue.add(new Entry("a", 1));
  17. // Entry [a:1]
  18. Entry e = queue.takeFirst();
  19. // Entry [c:1]
  20. Entry e = queue.takeLast();

7.20. Stream

Java implementation of Redis based Stream object wraps Redis Stream feature. Basically it allows to create Consumers Group which consume data added by Producers. This object is fully thread-safe.

  1. RStream<String, String> stream = redisson.getStream("test");
  2. StreamMessageId sm = stream.add(StreamAddArgs.entry("0", "0"));
  3. stream.createGroup("testGroup");
  4. StreamId id1 = stream.add(StreamAddArgs.entry("1", "1"));
  5. StreamId id2 = stream.add(StreamAddArgs.entry("2", "2"));
  6. Map<StreamId, Map<String, String>> group = stream.readGroup("testGroup", "consumer1", StreamReadGroupArgs.neverDelivered());
  7. // return entries in pending state after read group method execution
  8. Map<StreamMessageId, Map<String, String>> pendingData = stream.pendingRange("testGroup", "consumer1", StreamMessageId.MIN, StreamMessageId.MAX, 100);
  9. // transfer ownership of pending messages to a new consumer
  10. List<StreamMessageId> transferedIds = stream.fastClaim("testGroup", "consumer2", 1, TimeUnit.MILLISECONDS, id1, id2);
  11. // mark pending entries as correctly processed
  12. long amount = stream.ack("testGroup", id1, id2);

Code example of Async interface usage:

  1. RStream<String, String> stream = redisson.getStream("test");
  2. RFuture<StreamMessageId> smFuture = stream.addAsync(StreamAddArgs.entry("0", "0"));
  3. RFuture<Void> groupFuture = stream.createGroupAsync("testGroup");
  4. RFuture<StreamId> id1Future = stream.addAsync(StreamAddArgs.entry("1", "1"));
  5. RFuture<StreamId> id2Future = stream.addAsync(StreamAddArgs.entry("2", "2"));
  6. RFuture<Map<StreamId, Map<String, String>>> groupResultFuture = stream.readGroupAsync("testGroup", "consumer1", StreamReadGroupArgs.neverDelivered());
  7. // return entries in pending state after read group method execution
  8. RFuture<Map<StreamMessageId, Map<String, String>>> pendingDataFuture = stream.pendingRangeAsync("testGroup", "consumer1", StreamMessageId.MIN, StreamMessageId.MAX, 100);
  9. // transfer ownership of pending messages to a new consumer
  10. RFuture<List<StreamMessageId>> transferedIdsFuture = stream.fastClaim("testGroup", "consumer2", 1, TimeUnit.MILLISECONDS, id1, id2);
  11. // mark pending entries as correctly processed
  12. RFuture<Long> amountFuture = stream.ackAsync("testGroup", id1, id2);
  13. amountFuture.whenComplete((res, exception) -> {
  14. // ...
  15. });

Code example of Reactive interface usage:

  1. RedissonReactiveClient redisson = redissonClient.reactive();
  2. RStreamReactive<String, String> stream = redisson.getStream("test");
  3. Mono<StreamMessageId> smMono = stream.add(StreamAddArgs.entry("0", "0"));
  4. Mono<Void> groupMono = stream.createGroup("testGroup");
  5. Mono<StreamId> id1Mono = stream.add(StreamAddArgs.entry("1", "1"));
  6. Mono<StreamId> id2Mono = stream.add(StreamAddArgs.entry("2", "2"));
  7. Mono<Map<StreamId, Map<String, String>>> groupMono = stream.readGroup("testGroup", "consumer1", StreamReadGroupArgs.neverDelivered());
  8. // return entries in pending state after read group method execution
  9. Mono<Map<StreamMessageId, Map<String, String>>> pendingDataMono = stream.pendingRange("testGroup", "consumer1", StreamMessageId.MIN, StreamMessageId.MAX, 100);
  10. // transfer ownership of pending messages to a new consumer
  11. Mono<List<StreamMessageId>> transferedIdsMono = stream.fastClaim("testGroup", "consumer2", 1, TimeUnit.MILLISECONDS, id1, id2);
  12. // mark pending entries as correctly processed
  13. Mono<Long> amountMono = stream.ack("testGroup", id1, id2);
  14. amountMono.doOnNext(res -> {
  15. // ...
  16. }).subscribe();

Code example of RxJava3 interface usage:

  1. RedissonRxClient redisson = redissonClient.rxJava();
  2. RStreamRx<String, String> stream = redisson.getStream("test");
  3. Single<StreamMessageId> smRx = stream.add(StreamAddArgs.entry("0", "0"));
  4. Completable groupRx = stream.createGroup("testGroup");
  5. Single<StreamId> id1Rx = stream.add(StreamAddArgs.entry("1", "1"));
  6. Single<StreamId> id2Rx = stream.add(StreamAddArgs.entry("2", "2"));
  7. Single<Map<StreamId, Map<String, String>>> groupRx = stream.readGroup("testGroup", "consumer1", StreamReadGroupArgs.neverDelivered());
  8. // return entries in pending state after read group method execution
  9. Single<Map<StreamMessageId, Map<String, String>>> pendingDataRx = stream.pendingRange("testGroup", "consumer1", StreamMessageId.MIN, StreamMessageId.MAX, 100);
  10. // transfer ownership of pending messages to a new consumer
  11. Single<List<StreamMessageId>> transferedIdsRx = stream.fastClaim("testGroup", "consumer2", 1, TimeUnit.MILLISECONDS, id1, id2);
  12. // mark pending entries as correctly processed
  13. Single<Long> amountRx = stream.ack("testGroup", id1, id2);
  14. amountRx.doOnSuccess(res -> {
  15. // ...
  16. }).subscribe();

7.20.1. Stream listeners

Redisson allows to bind listeners per RStream object.

Listener class name Event description
org.redisson.api.listener.TrackingListener Element added/removed/updated after read operation
org.redisson.api.ExpiredObjectListener RStream object expired
org.redisson.api.DeletedObjectListener RStream object deleted
org.redisson.api.listener.StreamAddListener Element added
org.redisson.api.listener.StreamRemoveListener Element removed
org.redisson.api.listener.StreamCreateGroupListener Group created
org.redisson.api.listener.StreamRemoveGroupListener Group removed
org.redisson.api.listener.StreamCreateConsumerListener Consumer created
org.redisson.api.listener.StreamRemoveConsumerListener Consumer removed
org.redisson.api.listener.StreamTrimListener Stream trimmed

Usage example:

  1. RStream<String, String> stream = redisson.getStream("anySet");
  2. int listenerId = stream.addListener(new DeletedObjectListener() {
  3. @Override
  4. public void onDeleted(String name) {
  5. // ...
  6. }
  7. });
  8. int listenerId = stream.addListener(new StreamAddListener() {
  9. @Override
  10. public void onAdd(String name) {
  11. // ...
  12. }
  13. });
  14. // ...
  15. stream.removeListener(listenerId);

7.21. Ring Buffer

Java implementation of Redis based RingBuffer implements java.util.Queue interface. This structure evicts elements from the head if queue capacity became full. This object is fully thread-safe.

Should be initialized with capacity size by trySetCapacity() method before usage.

Code example:

  1. RRingBuffer<Integer> buffer = redisson.getRingBuffer("test");
  2. // buffer capacity is 4 elements
  3. buffer.trySetCapacity(4);
  4. buffer.add(1);
  5. buffer.add(2);
  6. buffer.add(3);
  7. buffer.add(4);
  8. // buffer state is 1, 2, 3, 4
  9. buffer.add(5);
  10. buffer.add(6);
  11. // buffer state is 3, 4, 5, 6

Code example of Async interface usage:

  1. RRingBuffer<Integer> buffer = redisson.getRingBuffer("test");
  2. // buffer capacity is 4 elements
  3. RFuture<Boolean> capacityFuture = buffer.trySetCapacityAsync(4);
  4. RFuture<Boolean> addFuture = buffer.addAsync(1);
  5. RFuture<Boolean> addFuture = buffer.addAsync(2);
  6. RFuture<Boolean> addFuture = buffer.addAsync(3);
  7. RFuture<Boolean> addFuture = buffer.addAsync(4);
  8. // buffer state is 1, 2, 3, 4
  9. RFuture<Boolean> addFuture = buffer.addAsync(5);
  10. RFuture<Boolean> addFuture = buffer.addAsync(6);
  11. // buffer state is 3, 4, 5, 6
  12. addFuture.whenComplete((res, exception) -> {
  13. // ...
  14. });

Code example of Reactive interface usage:

  1. RedissonReactiveClient redisson = redissonClient.reactive();
  2. RRingBufferReactive<Integer> buffer = redisson.getRingBuffer("test");
  3. // buffer capacity is 4 elements
  4. Mono<Boolean> capacityMono = buffer.trySetCapacity(4);
  5. Mono<Boolean> addMono = buffer.add(1);
  6. Mono<Boolean> addMono = buffer.add(2);
  7. Mono<Boolean> addMono = buffer.add(3);
  8. Mono<Boolean> addMono = buffer.add(4);
  9. // buffer state is 1, 2, 3, 4
  10. Mono<Boolean> addMono = buffer.add(5);
  11. Mono<Boolean> addMono = buffer.add(6);
  12. // buffer state is 3, 4, 5, 6
  13. addMono.doOnNext(res -> {
  14. // ...
  15. }).subscribe();

Code example of RxJava3 interface usage:

  1. RedissonRxClient redisson = redissonClient.rxJava();
  2. RRingBufferRx<Integer> buffer = redisson.getRingBuffer("test");
  3. // buffer capacity is 4 elements
  4. Single<Boolean> capacityRx = buffer.trySetCapacity(4);
  5. Single<Boolean> addRx = buffer.add(1);
  6. Single<Boolean> addRx = buffer.add(2);
  7. Single<Boolean> addRx = buffer.add(3);
  8. Single<Boolean> addRx = buffer.add(4);
  9. // buffer state is 1, 2, 3, 4
  10. Single<Boolean> addRx = buffer.add(5);
  11. Single<Boolean> addRx = buffer.add(6);
  12. // buffer state is 3, 4, 5, 6
  13. addRx.doOnSuccess(res -> {
  14. // ...
  15. }).subscribe();

7.21.1. Ring Buffer listeners

Redisson allows to bind listeners per RRingBuffer object.

Listener class name Event description
org.redisson.api.listener.TrackingListener Element created/removed/updated after read operation
org.redisson.api.listener.ListAddListener Element created
org.redisson.api.listener.ListRemoveListener Element removed
org.redisson.api.ExpiredObjectListener RRingBuffer object expired
org.redisson.api.DeletedObjectListener RRingBuffer object deleted

Usage example:

  1. RRingBuffer<String> queue = redisson.getRingBuffer("anyList");
  2. int listenerId = queue.addListener(new DeletedObjectListener() {
  3. @Override
  4. public void onDeleted(String name) {
  5. // ...
  6. }
  7. });
  8. // ...
  9. queue.removeListener(listenerId);

7.22. Transfer Queue

Java implementation of Redis based TransferQueue implements java.util.concurrent.TransferQueue interface. Provides set of transfer methods which return only when value was successfully hand off to consumer. This object is fully thread-safe.

poll and take methods are resubscribed automatically during re-connection to Redis server or failover.

Code example:

  1. RTransferQueue<String> queue = redisson.getTransferQueue("myCountDownLatch");
  2. queue.transfer("data");
  3. // or try transfer immediately
  4. queue.tryTransfer("data");
  5. // or try transfer up to 10 seconds
  6. queue.tryTransfer("data", 10, TimeUnit.SECONDS);
  7. // in other thread or JVM
  8. queue.take();
  9. // or
  10. queue.poll();

Code example of Async interface usage:

  1. RTransferQueue<String> queue = redisson.getTransferQueue("myCountDownLatch");
  2. RFuture<Void> future = queue.transferAsync("data");
  3. // or try transfer immediately
  4. RFuture<Boolean> future = queue.tryTransferAsync("data");
  5. // or try transfer up to 10 seconds
  6. RFuture<Boolean> future = queue.tryTransferAsync("data", 10, TimeUnit.SECONDS);
  7. // in other thread or JVM
  8. RFuture<String> future = queue.takeAsync();
  9. // or
  10. RFuture<String> future = queue.pollAsync();
  11. future.whenComplete((res, exception) -> {
  12. // ...
  13. });

Code example of Reactive interface usage:

  1. RedissonReactiveClient redisson = redissonClient.reactive();
  2. RTransferQueueReactive<String> queue = redisson.getTransferQueue("myCountDownLatch");
  3. Mono<Void> mono = queue.transfer("data");
  4. // or try transfer immediately
  5. Mono<Boolean> mono = queue.tryTransfer("data");
  6. // or try transfer up to 10 seconds
  7. Mono<Boolean> mono = queue.tryTransfer("data", 10, TimeUnit.SECONDS);
  8. // in other thread or JVM
  9. Mono<String> mono = queue.take();
  10. // or
  11. Mono<String> mono = queue.poll();
  12. mono.doOnNext(res -> {
  13. // ...
  14. }).subscribe();

Code example of RxJava3 interface usage:

  1. RedissonRxClient redisson = redissonClient.rxJava();
  2. RTransferQueueRx<String> queue = redisson.getTransferQueue("myCountDownLatch");
  3. Completable res = queue.transfer("data");
  4. // or try transfer immediately
  5. Single<Boolean> resRx = queue.tryTransfer("data");
  6. // or try transfer up to 10 seconds
  7. Single<Boolean> resRx = queue.tryTransfer("data", 10, TimeUnit.SECONDS);
  8. // in other thread or JVM
  9. Single<String> resRx = queue.take();
  10. // or
  11. Maybe<String> resRx = queue.poll();
  12. resRx.doOnSuccess(res -> {
  13. // ...
  14. }).subscribe();

7.23. Time Series

Java implementation of Redis based TimeSeries object allows to store value by timestamp and define TTL(time-to-live) per entry. Values are ordered by timestamp. This object is fully thread-safe.

Code example:

  1. RTimeSeries<String> ts = redisson.getTimeSeries("myTimeSeries");
  2. ts.add(201908110501, "10%");
  3. ts.add(201908110502, "30%");
  4. ts.add(201908110504, "10%");
  5. ts.add(201908110508, "75%");
  6. // entry time-to-live is 10 hours
  7. ts.add(201908110510, "85%", 10, TimeUnit.HOURS);
  8. ts.add(201908110510, "95%", 10, TimeUnit.HOURS);
  9. String value = ts.get(201908110508);
  10. ts.remove(201908110508);
  11. Collection<String> values = ts.pollFirst(2);
  12. Collection<String> range = ts.range(201908110501, 201908110508);

Code example of Async interface usage:

  1. RTimeSeries<String> ts = redisson.getTimeSeries("myTimeSeries");
  2. RFuture<Void> future = ts.addAsync(201908110501, "10%");
  3. RFuture<Void> future = ts.addAsync(201908110502, "30%");
  4. RFuture<Void> future = ts.addAsync(201908110504, "10%");
  5. RFuture<Void> future = ts.addAsync(201908110508, "75%");
  6. // entry time-to-live is 10 hours
  7. RFuture<Void> future = ts.addAsync(201908110510, "85%", 10, TimeUnit.HOURS);
  8. RFuture<Void> future = ts.addAsync(201908110510, "95%", 10, TimeUnit.HOURS);
  9. RFuture<String> future = ts.getAsync(201908110508);
  10. RFuture<Boolean> future = ts.removeAsync(201908110508);
  11. RFuture<Collection<String>> future = t.pollFirstAsync(2);
  12. RFuture<Collection<String>> future = t.rangeAsync(201908110501, 201908110508);
  13. future.whenComplete((res, exception) -> {
  14. // ...
  15. });

Code example of Reactive interface usage:

  1. RedissonReactiveClient redisson = redissonClient.reactive();
  2. RTimeSeriesReactive<String> ts = redisson.getTimeSeries("myTimeSeries");
  3. Mono<Void> mono = ts.add(201908110501, "10%");
  4. Mono<Void> mono = ts.add(201908110502, "30%");
  5. Mono<Void> mono = ts.add(201908110504, "10%");
  6. Mono<Void> mono = ts.add(201908110508, "75%");
  7. // entry time-to-live is 10 hours
  8. Mono<Void> mono = ts.add(201908110510, "85%", 10, TimeUnit.HOURS);
  9. Mono<Void> mono = ts.add(201908110510, "95%", 10, TimeUnit.HOURS);
  10. Mono<String> mono = ts.get(201908110508);
  11. Mono<Boolean> mono = ts.remove(201908110508);
  12. Mono<Collection<String>> mono = ts.pollFirst(2);
  13. Mono<Collection<String>> mono = ts.range(201908110501, 201908110508);
  14. mono.doOnNext(res -> {
  15. // ...
  16. }).subscribe();

Code example of RxJava3 interface usage:

  1. RedissonRxClient redisson = redissonClient.rxJava();
  2. RTimeSeriesRx<String> ts = redisson.getTimeSeries("myTimeSeries");
  3. Completable rx = ts.add(201908110501, "10%");
  4. Completable rx = ts.add(201908110502, "30%");
  5. Completable rx = ts.add(201908110504, "10%");
  6. Completable rx = ts.add(201908110508, "75%");
  7. // entry time-to-live is 10 hours
  8. Completable rx = ts.add(201908110510, "85%", 10, TimeUnit.HOURS);
  9. Completable rx = ts.add(201908110510, "95%", 10, TimeUnit.HOURS);
  10. Maybe<String> rx = ts.get(201908110508);
  11. Single<Boolean> rx = ts.remove(201908110508);
  12. Single<Collection<String>> rx = ts.pollFirst(2);
  13. Single<Collection<String>> rx = ts.range(201908110501, 201908110508);
  14. rx.doOnSuccess(res -> {
  15. // ...
  16. }).subscribe();