Map
Redis or Valkey based distributed Map object for Java implements ConcurrentMap interface. This object is thread-safe. Consider to use Live Object service to store POJO object as Redis or Valkey Map. Redis or Valkey uses serialized state to check key uniqueness instead of key’s hashCode()/equals() methods.
If Map used mostly for read operations and/or network roundtrips are undesirable use Map with Local cache support.
Code examples:
RMap<String, SomeObject> map = redisson.getMap("anyMap");SomeObject prevObject = map.put("123", new SomeObject());SomeObject currentObject = map.putIfAbsent("323", new SomeObject());SomeObject obj = map.remove("123");// use fast* methods when previous value is not requiredmap.fastPut("a", new SomeObject());map.fastPutIfAbsent("d", new SomeObject());map.fastRemove("b");RFuture<SomeObject> putAsyncFuture = map.putAsync("321");RFuture<Void> fastPutAsyncFuture = map.fastPutAsync("321");map.fastPutAsync("321", new SomeObject());map.fastRemoveAsync("321");
RMap object allows to bind a Lock/ReadWriteLock/Semaphore/CountDownLatch object per key:
RMap<MyKey, MyValue> map = redisson.getMap("anyMap");MyKey k = new MyKey();RLock keyLock = map.getLock(k);keyLock.lock();try {MyValue v = map.get(k);// process value ...} finally {keyLock.unlock();}RReadWriteLock rwLock = map.getReadWriteLock(k);rwLock.readLock().lock();try {MyValue v = map.get(k);// process value ...} finally {keyLock.readLock().unlock();}
Eviction, local cache and data partitioning
Redisson provides various Map structure implementations with multiple 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. It’s recommended to use each local cached instance as a singleton per unique name since it has own state for local cache.
data partitioning - although any Map object is cluster compatible its content isn’t scaled/partitioned across multiple master nodes in cluster. Data partitioning allows to scale available memory, read/write operations and entry eviction process for individual Map instance in cluster.
1. No eviction
Each object implements RMap, Async, Reactive and RxJava3 interfaces.
Available implementations:
| RedissonClient method name |
Local cache |
Data partitioning |
Ultra-fast read/write |
|---|---|---|---|
| getMap() open-source version |
❌ | ❌ | ❌ |
| getLocalCachedMap() open-source version |
✔️ | ❌ | ❌ |
| getMap() Redisson PRO version |
❌ | ❌ | ✔️ |
| getLocalCachedMap() Redisson PRO version |
✔️ | ❌ | ✔️ |
| getClusteredMap() available only in Redisson PRO |
❌ | ✔️ | ✔️ |
| getClusteredLocalCachedMap() available only in Redisson PRO |
✔️ | ✔️ | ✔️ |
2. Scripted eviction
Allows to define time to live or max idle time parameters per map entry. Eviction is done on Redisson side through a custom scheduled task which removes expired entries using Lua script. Eviction task is started once per unique object name at the moment of getting Map instance. If instance isn’t used and has expired entries it should be get again to start the eviction process. This leads to extra Redis or Valkey calls and eviction task per unique map object name.
Entries are cleaned time to time by org.redisson.eviction.EvictionScheduler. By default, it removes 100 expired entries at a time. This can be changed through cleanUpKeysAmount setting. Task launch time tuned automatically and depends on expired entries amount deleted in previous time and varies between 5 second to 30 minutes by default. This time interval can be changed through minCleanUpDelay and maxCleanUpDelay. For example, 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.
Each object implements RMapCache, Async, Reactive and RxJava3 interfaces.
Available implementations:
| RedissonClient method name |
Local cache |
Data partitioning |
Ultra-fast read/write |
|---|---|---|---|
| getMapCache() open-source version |
❌ | ❌ | ❌ |
| getMapCache() Redisson PRO version |
❌ | ❌ | ✔️ |
| getLocalCachedMapCache() available only in Redisson PRO |
✔️ | ❌ | ✔️ |
| getClusteredMapCache() available only in Redisson PRO |
❌ | ✔️ | ✔️ |
| getClusteredLocalCachedMapCache() available only in Redisson PRO |
✔️ | ✔️ | ✔️ |
3. Advanced eviction
Allows to define time to live parameter per map entry. Doesn’t use an entry eviction task, entries are cleaned on Redis or Valkey side.
Each object implements RMapCacheV2, Async, Reactive and RxJava3 interfaces.
Available implementations:
| RedissonClient method name |
Local cache |
Data partitioning |
Ultra-fast read/write |
|---|---|---|---|
| getMapCacheV2() available only in Redisson PRO |
❌ | ✔️ | ✔️ |
| getLocalCachedMapCacheV2() available only in Redisson PRO |
✔️ | ✔️ | ✔️ |
4. Native eviction
Allows to define time to live parameter per map entry. Doesn’t use an entry eviction task, entries are cleaned on Redis side. Requires Redis 7.4+.
Each object implements RMapCacheNative, Async, Reactive and RxJava3 interfaces.
Available implementations:
| RedissonClient method name |
Local cache |
Data partitioning |
Ultra-fast read/write |
|---|---|---|---|
| getMapCacheNative() open-source version |
❌ | ❌ | ❌ |
| getMapCacheNative() Redisson PRO version |
❌ | ❌ | ✔️ |
| getLocalCachedMapCacheNative() available only in Redisson PRO |
✔️ | ❌ | ✔️ |
| getClusteredMapCacheNative() available only in Redisson PRO |
❌ | ✔️ | ✔️ |
Redisson also provides various Cache API implementations.
It’s recommended to use single instance of Map instance with the same name for each Redisson client instance.
Code example:
RMapCache<String, SomeObject> map = redisson.getMapCache("anyMap");// orRMapCache<String, SomeObject> map = redisson.getMapCache("anyMap", MapCacheOptions.defaults());// orRMapCacheV2<String, SomeObject> map = redisson.getMapCacheV2("anyMap");// orRMapCacheV2<String, SomeObject> map = redisson.getMapCacheV2("anyMap", MapOptions.defaults());// orRMapCache<String, SomeObject> map = redisson.getLocalCachedMapCache("anyMap", LocalCachedMapOptions.defaults());// orRMapCache<String, SomeObject> map = redisson.getClusteredLocalCachedMapCache("anyMap", LocalCachedMapOptions.defaults());// orRMapCache<String, SomeObject> map = redisson.getClusteredMapCache("anyMap");// orRMapCache<String, SomeObject> map = redisson.getClusteredMapCache("anyMap", MapCacheOptions.defaults());// ttl = 10 minutes,map.put("key1", new SomeObject(), 10, TimeUnit.MINUTES);// ttl = 10 minutes, maxIdleTime = 10 secondsmap.put("key1", new SomeObject(), 10, TimeUnit.MINUTES, 10, TimeUnit.SECONDS);// ttl = 3 secondsmap.putIfAbsent("key2", new SomeObject(), 3, TimeUnit.SECONDS);// ttl = 40 seconds, maxIdleTime = 10 secondsmap.putIfAbsent("key2", new SomeObject(), 40, TimeUnit.SECONDS, 10, TimeUnit.SECONDS);// if object is not used anymoremap.destroy();
Local cache
Map object with local cache support implements RLocalCachedMap which extends ConcurrentMap interface. This object is 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 can be supplied during object creation:
LocalCachedMapOptions options = LocalCachedMapOptions.defaults()// Defines whether to store a cache miss into the local cache.// Default value is false..storeCacheMiss(false);// Defines store mode of cache data.// Follow options are available:// LOCALCACHE - store data in local cache only and use Redis or Valkey only for data update/invalidation.// LOCALCACHE_REDIS - store data in both Redis or Valkey and local cache..storeMode(StoreMode.LOCALCACHE_REDIS)// Defines Cache provider used as local cache store.// Follow options are available:// REDISSON - uses Redisson own implementation// CAFFEINE - uses Caffeine implementation.cacheProvider(CacheProvider.REDISSON)// Defines local cache eviction policy.// Follow options are available:// LFU - Counts how often an item was requested. Those that are used least often are discarded first.// LRU - Discards the least recently used items first// SOFT - Uses soft references, entries are removed by GC// WEAK - Uses weak references, entries are removed by GC// NONE - No eviction.evictionPolicy(EvictionPolicy.NONE)// If cache size is 0 then local cache is unbounded..cacheSize(1000)// Defines strategy for load missed local cache updates after connection failure.//// Follow reconnection strategies are available:// CLEAR - Clear local cache if map instance has been disconnected for a while.// LOAD - Store invalidated entry hash in invalidation log for 10 minutes// Cache keys for stored invalidated entry hashes will be removed// if LocalCachedMap instance has been disconnected less than 10 minutes// or whole cache will be cleaned otherwise.// NONE - Default. No reconnection handling.reconnectionStrategy(ReconnectionStrategy.NONE)// Defines local cache synchronization strategy.//// Follow sync strategies are available:// INVALIDATE - Default. Invalidate cache entry across all LocalCachedMap instances on map entry change// UPDATE - Insert/update cache entry across all LocalCachedMap instances on map entry change// NONE - No synchronizations on map changes.syncStrategy(SyncStrategy.INVALIDATE)// time to live for each entry in local cache.timeToLive(Duration.ofSeconds(10))// max idle time for each map entry in local cache.maxIdle(Duration.ofSeconds(10))// Defines how to listen expired event sent by Redis or Valkey upon this instance deletion//// Follow expiration policies are available:// DONT_SUBSCRIBE - Don't subscribe on expire event// SUBSCRIBE_WITH_KEYEVENT_PATTERN - Subscribe on expire event using `__keyevent@*:expired` pattern// SUBSCRIBE_WITH_KEYSPACE_CHANNEL - Subscribe on expire event using `__keyspace@N__:name` channel.expirationEventPolicy(ExpirationEventPolicy.SUBSCRIBE_WITH_KEYEVENT_PATTERN);
Code example:
RLocalCachedMap<String, Integer> map = redisson.getLocalCachedMap("test", LocalCachedMapOptions.defaults());// orRLocalCachedMap<String, SomeObject> map = redisson.getLocalCachedMapCache("anyMap", LocalCachedMapCacheOptions.defaults());// orRLocalCachedMap<String, SomeObject> map = redisson.getClusteredLocalCachedMapCache("anyMap", LocalCachedMapCacheOptions.defaults());// orRLocalCachedMap<String, SomeObject> map = redisson.getClusteredLocalCachedMap("anyMap", LocalCachedMapOptions.defaults());String prevObject = map.put("123", 1);String currentObject = map.putIfAbsent("323", 2);String obj = map.remove("123");// use fast* methods when previous value is not requiredmap.fastPut("a", 1);map.fastPutIfAbsent("d", 32);map.fastRemove("b");RFuture<String> putAsyncFuture = map.putAsync("321");RFuture<Void> fastPutAsyncFuture = map.fastPutAsync("321");map.fastPutAsync("321", new SomeObject());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.
RLocalCachedMap<String, Integer> map = ...map.destroy();
How to load data and avoid invalidation messages traffic.
Code example:
public void loadData(String cacheName, Map<String, String> data) {RLocalCachedMap<String, String> clearMap = redisson.getLocalCachedMap(cacheName,LocalCachedMapOptions.defaults().cacheSize(1).syncStrategy(SyncStrategy.INVALIDATE));RLocalCachedMap<String, String> loadMap = redisson.getLocalCachedMap(cacheName,LocalCachedMapOptions.defaults().cacheSize(1).syncStrategy(SyncStrategy.NONE));loadMap.putAll(data);clearMap.clearLocalCache();}
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:
RClusteredMap<String, SomeObject> map = redisson.getClusteredMap("anyMap");// orRClusteredMap<String, SomeObject> map = redisson.getClusteredLocalCachedMapCache("anyMap", LocalCachedMapCacheOptions.defaults());// orRClusteredMap<String, SomeObject> map = redisson.getClusteredLocalCachedMap("anyMap", LocalCachedMapOptions.defaults());// orRClusteredMap<String, SomeObject> map = redisson.getClusteredMapCache("anyMap");SomeObject prevObject = map.put("123", new SomeObject());SomeObject currentObject = map.putIfAbsent("323", new SomeObject());SomeObject obj = map.remove("123");map.fastPut("321", new SomeObject());map.fastRemove("321");
Persistence
Redisson allows to store Map data in external storage along with Redis or Valkey store. Use cases:
- Redisson Map object as a cache between an application and external storage.
- Increase durability of Redisson Map data and life-span of evicted entries.
- 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:
MapLoader<String, String> mapLoader = new MapLoader<String, String>() {@Overridepublic Iterable<String> loadAllKeys() {List<String> list = new ArrayList<String>();Statement statement = conn.createStatement();try {ResultSet result = statement.executeQuery("SELECT id FROM student");while (result.next()) {list.add(result.getString(1));}} finally {statement.close();}return list;}@Overridepublic String load(String key) {PreparedStatement preparedStatement = conn.prepareStatement("SELECT name FROM student where id = ?");try {preparedStatement.setString(1, key);ResultSet result = preparedStatement.executeQuery();if (result.next()) {return result.getString(1);}return null;} finally {preparedStatement.close();}}};
Configuration example:
MapOptions<K, V> options = MapOptions.<K, V>defaults().loader(mapLoader);MapCacheOptions<K, V> mcoptions = MapCacheOptions.<K, V>defaults().loader(mapLoader);RMap<K, V> map = redisson.getMap("test", options);// orRMapCache<K, V> map = redisson.getMapCache("test", mcoptions);// or with performance boost up to 45x timesRLocalCachedMap<K, V> map = redisson.getLocalCachedMap("test", options);// or with performance boost up to 45x timesRLocalCachedMapCache<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:
MapWriter<String, String> mapWriter = new MapWriter<String, String>() {@Overridepublic void write(Map<String, String> map) {PreparedStatement preparedStatement = conn.prepareStatement("INSERT INTO student (id, name) values (?, ?)");try {for (Entry<String, String> entry : map.entrySet()) {preparedStatement.setString(1, entry.getKey());preparedStatement.setString(2, entry.getValue());preparedStatement.addBatch();}preparedStatement.executeBatch();} finally {preparedStatement.close();}}@Overridepublic void delete(Collection<String> keys) {PreparedStatement preparedStatement = conn.prepareStatement("DELETE FROM student where id = ?");try {for (String key : keys) {preparedStatement.setString(1, key);preparedStatement.addBatch();}preparedStatement.executeBatch();} finally {preparedStatement.close();}}};
Configuration example:
MapOptions<K, V> options = MapOptions.<K, V>defaults().writer(mapWriter).writeMode(WriteMode.WRITE_THROUGH);MapCacheOptions<K, V> mcoptions = MapCacheOptions.<K, V>defaults().writer(mapWriter).writeMode(WriteMode.WRITE_THROUGH);RMap<K, V> map = redisson.getMap("test", options);// orRMapCache<K, V> map = redisson.getMapCache("test", mcoptions);// or with performance boost up to 45x timesRLocalCachedMap<K, V> map = redisson.getLocalCachedMap("test", options);// or with performance boost up to 45x timesRLocalCachedMapCache<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:
MapOptions<K, V> options = MapOptions.<K, V>defaults().writer(mapWriter).writeMode(WriteMode.WRITE_BEHIND).writeBehindDelay(5000).writeBehindBatchSize(100);MapCacheOptions<K, V> mcoptions = MapCacheOptions.<K, V>defaults().writer(mapWriter).writeMode(WriteMode.WRITE_BEHIND).writeBehindDelay(5000).writeBehindBatchSize(100);RMap<K, V> map = redisson.getMap("test", options);// orRMapCache<K, V> map = redisson.getMapCache("test", mcoptions);// or with performance boost up to 45x timesRLocalCachedMap<K, V> map = redisson.getLocalCachedMap("test", options);// or with performance boost up to 45x timesRLocalCachedMapCache<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 or Valkey read-operations up to 45x times and give almost instant speed for database, web service or any other data source.
Listeners
Redisson allows binding listeners per RMap object. This requires the notify-keyspace-events setting to be enabled on Redis or Valkey side.
RMap object allows to track follow events over the data.
| Listener class name | Event description | Redis or Valkeynotify-keyspace-events value |
|---|---|---|
| org.redisson.api.listener.TrackingListener | Entry created/removed/updated after read operation | - |
| org.redisson.api.listener.MapPutListener | Entry created/updated | Eh |
| org.redisson.api.listener.MapRemoveListener | Entry removed | Eh |
| org.redisson.api.ExpiredObjectListener | RMap object expired |
Ex |
| org.redisson.api.DeletedObjectListener | RMap object deleted |
Eg |
Usage examples:
RMap<String, SomeObject> map = redisson.getMap("anyMap");int listenerId = map.addListener(new DeletedObjectListener() {@Overridepublic void onDeleted(String name) {// ...}});int listenerId = map.addListener(new ExpiredObjectListener() {@Overridepublic void onExpired(String name) {// ...}});int listenerId = map.addListener(new MapPutListener() {@Overridepublic void onPut(String name) {// ...}});int listenerId = map.addListener(new MapRemoveListener() {@Overridepublic void onRemove(String name) {// ...}});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:
RMapCache<String, SomeObject> map = redisson.getMapCache("anyMap");// orRMapCache<String, SomeObject> map = redisson.getLocalCachedMapCache(LocalCachedMapCacheOptions.name("anyMap"));// orRMapCache<String, SomeObject> map = redisson.getClusteredLocalCachedMapCache("anyMap", LocalCachedMapOptions.defaults());// orRMapCache<String, SomeObject> map = redisson.getClusteredMapCache("anyMap");int listenerId = map.addListener(new EntryUpdatedListener<Integer, Integer>() {@Overridepublic void onUpdated(EntryEvent<Integer, Integer> event) {event.getKey(); // keyevent.getValue() // new valueevent.getOldValue() // old value// ...}});int listenerId = map.addListener(new EntryCreatedListener<Integer, Integer>() {@Overridepublic void onCreated(EntryEvent<Integer, Integer> event) {event.getKey(); // keyevent.getValue() // value// ...}});int listenerId = map.addListener(new EntryExpiredListener<Integer, Integer>() {@Overridepublic void onExpired(EntryEvent<Integer, Integer> event) {event.getKey(); // keyevent.getValue() // value// ...}});int listenerId = map.addListener(new EntryRemovedListener<Integer, Integer>() {@Overridepublic void onRemoved(EntryEvent<Integer, Integer> event) {event.getKey(); // keyevent.getValue() // value// ...}});map.removeListener(listenerId);
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 or Valkey memory.
RMapCache<String, SomeObject> map = redisson.getMapCache("anyMap");// orRMapCache<String, SomeObject> map = redisson.getMapCache("anyMap", MapCacheOptions.defaults());// orRMapCache<String, SomeObject> map = redisson.getLocalCachedMapCache("anyMap", LocalCachedMapOptions.defaults());// orRMapCache<String, SomeObject> map = redisson.getClusteredLocalCachedMapCache("anyMap", LocalCachedMapOptions.defaults());// orRMapCache<String, SomeObject> map = redisson.getClusteredMapCache("anyMap");// orRMapCache<String, SomeObject> map = redisson.getClusteredMapCache("anyMap", MapCacheOptions.defaults());// tries to set limit map to 10 entries using LRU eviction algorithmmap.trySetMaxSize(10);// ... using LFU eviction algorithmmap.trySetMaxSize(10, EvictionMode.LFU);// set or change limit map to 10 entries using LRU eviction algorithmmap.setMaxSize(10);// ... using LFU eviction algorithmmap.setMaxSize(10, EvictionMode.LFU);map.put("1", "2");map.put("3", "3", 1, TimeUnit.SECONDS);
Multimap
Redis or Valkey based Multimap for Java allows to bind multiple values per key. This object is thread-safe. Keys amount limited to 4 294 967 295 elements. Redis or Valkey uses serialized state to check key uniqueness instead of key’s hashCode()/equals() methods.
It has Async, Reactive and RxJava3 interfaces.
Set based Multimap
Set based Multimap doesn’t allow duplications for values per key.
RSetMultimap<SimpleKey, SimpleValue> map = redisson.getSetMultimap("myMultimap");map.put(new SimpleKey("0"), new SimpleValue("1"));map.put(new SimpleKey("0"), new SimpleValue("2"));map.put(new SimpleKey("3"), new SimpleValue("4"));Set<SimpleValue> allValues = map.get(new SimpleKey("0"));List<SimpleValue> newValues = Arrays.asList(new SimpleValue("7"), new SimpleValue("6"), new SimpleValue("5"));Set<SimpleValue> oldValues = map.replaceValues(new SimpleKey("0"), newValues);Set<SimpleValue> removedValues = map.removeAll(new SimpleKey("0"));
List based Multimap
List based Multimap object for Java stores entries in insertion order and allows duplicates for values mapped to key.
RListMultimap<SimpleKey, SimpleValue> map = redisson.getListMultimap("test1");map.put(new SimpleKey("0"), new SimpleValue("1"));map.put(new SimpleKey("0"), new SimpleValue("2"));map.put(new SimpleKey("0"), new SimpleValue("1"));map.put(new SimpleKey("3"), new SimpleValue("4"));List<SimpleValue> allValues = map.get(new SimpleKey("0"));Collection<SimpleValue> newValues = Arrays.asList(new SimpleValue("7"), new SimpleValue("6"), new SimpleValue("5"));List<SimpleValue> oldValues = map.replaceValues(new SimpleKey("0"), newValues);List<SimpleValue> removedValues = map.removeAll(new SimpleKey("0"));
Eviction
Multimap distributed object for Java with eviction support implemented by separated MultimapCache object. There are RSetMultimapCache and RListMultimapCache objects for Set and List based Multimaps respectively.
Eviction task is started once per unique object name at the moment of getting Multimap instance. If instance isn’t used and has expired entries it should be get again to start the eviction process. This leads to extra Redis or Valkey calls and eviction task per unique map object name.
Entries are cleaned time to time by org.redisson.eviction.EvictionScheduler. By default, it removes 100 expired entries at a time. This can be changed through cleanUpKeysAmount setting. Task launch time tuned automatically and depends on expired entries amount deleted in previous time and varies between 5 second to 30 minutes by default. This time interval can be changed through minCleanUpDelay and maxCleanUpDelay. For example, 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.
RSetMultimapCache example:
RSetMultimapCache<String, String> multimap = redisson.getSetMultimapCache("myMultimap");multimap.put("1", "a");multimap.put("1", "b");multimap.put("1", "c");multimap.put("2", "e");multimap.put("2", "f");multimap.expireKey("2", 10, TimeUnit.MINUTES);// if object is not used anymoremultimap.destroy();
Listeners
Redisson allows binding listeners per RSetMultimap or RListMultimap object. This requires the notify-keyspace-events setting to be enabled on Redis or Valkey side.
RSetMultimap listeners:
| Listener class name | Event description | Valkey or Redisnotify-keyspace-events value |
|---|---|---|
| org.redisson.api.ExpiredObjectListener | RSetMultimap object expired |
Ex |
| org.redisson.api.DeletedObjectListener | RSetMultimap object deleted |
Eg |
| org.redisson.api.listener.SetAddListener | Element added to entry | Es |
| org.redisson.api.listener.SetRemoveListener | Element removed from entry | Es |
| org.redisson.api.listener.MapPutListener | Entry created | Eh |
| org.redisson.api.listener.MapRemoveListener | Entry removed | Eh |
RListMultimap listeners:
| Listener class name | Event description | Valkey or Redisnotify-keyspace-events value |
|---|---|---|
| org.redisson.api.ExpiredObjectListener | RListMultimap object expired |
Ex |
| org.redisson.api.DeletedObjectListener | RListMultimap object deleted |
Eg |
| org.redisson.api.listener.ListAddListener | Element added to entry | Es |
| org.redisson.api.listener.ListRemoveListener | Element removed from entry | Es |
| org.redisson.api.listener.MapPutListener | Entry created | Eh |
| org.redisson.api.listener.MapRemoveListener | Entry removed | Eh |
Usage example:
RListMultimap<Integer, Integer> lmap = redisson.getListMultimap("mymap");int listenerId = lmap.addListener(new MapPutListener() {@Overridepublic void onPut(String name) {// ...}});// ...lmap.removeListener(listenerId);
JSON Store
This feature is available only in Redisson PRO edition.
RJsonStore is a distributed Key Value store for JSON objects. Compatible with Redis or Valkey. This object is thread-safe. Allows to store JSON value mapped by key. Operations can be executed per key or group of keys. Value is stored/retrieved using JSON.* commands. Both key and value are POJO objects.
Allows to define time to live parameter per entry. Doesn’t use an entry eviction task, entries are cleaned on Redis or Valkey side.
Code example of Async interface usage:
RJsonStoreAsync<String, MyObject> store = redisson.getJsonStore("test", new JacksonCodec(MyObject.class));
Code example of Reactive interface usage:
RedissonReactiveClient redisson = redissonClient.reactive();RJsonStoreReactive<AnyObject> bucket = redisson.getJsonStore("anyObject", new JacksonCodec<>(AnyObject.class));
Code example of RxJava3 interface usage:
RedissonRxClient redisson = redissonClient.rxJava();RJsonStoreRx<AnyObject> bucket = redisson.getJsonStore("anyObject", new JacksonCodec<>(AnyObject.class));
Data write code example:
RJsonStore<String, MyObject> store = redisson.getJsonStore("test", new JacksonCodec(MyObject.class));MyObject t1 = new MyObject();t1.setName("name1");MyObject t2 = new MyObject();t2.setName("name2");Map<String, MyObject> entries = new HashMap<>();entries.put("1", t1);entries.put("2", t2);// multiple entries at oncestore.set(entries);// or set entry per callstore.set("1", t1);store.set("2", t2);// with ttlstore.set("1", t1, Duration.ofSeconds(100));// set if not set previouslystore.setIfAbsent("1", t1);// set if entry already existsstore.setIfExists("1", t1);
Data read code example:
RJsonStore<String, MyObject> store = redisson.getJsonStore("test", new JacksonCodec(MyObject.class));// multiple entries at onceMap<String, MyObject> entries = store.get(Set.of("1", "2"));// or read entry per callMyObject value1 = store.get("1");MyObject value2 = store.get("2");
Data deletion code example:
RJsonStore<String, MyObject> store = redisson.getJsonStore("test", new JacksonCodec(MyObject.class));// multiple entries at oncelong deleted = store.delete(Set.of("1", "2"));// or delete entry per callboolean status = store.delete("1");boolean status = store.delete("2");
Keys access code examples:
RJsonStore<String, MyObject> store = redisson.getJsonStore("test", new JacksonCodec(MyObject.class));// iterate keysSet<String> keys = store.keySet();// read all keys at onceSet<String> keys = store.readAllKeySet();
Search by Object properties
For data searching, index prefix should be defined in <object_name>: format. For example for object name “test” prefix is “test:”.
StringCodec should be used as object codec to enable searching by field.
Data search code example:
RSearch s = redisson.getSearch();s.createIndex("idx", IndexOptions.defaults().on(IndexType.JSON).prefix(Arrays.asList("test:")),FieldIndex.text("name"));RJsonStore<String, MyObject> store = redisson.getJsonStore("test", StringCodec.INSTANCE, new JacksonCodec(MyObject.class));MyObject t1 = new MyObject();t1.setName("name1");MyObject t2 = new MyObject();t2.setName("name2");Map<String, MyObject> entries = new HashMap<>();entries.put("1", t1);entries.put("2", t2);store.set(entries);// searchSearchResult r = s.search("idx", "*", QueryOptions.defaults().returnAttributes(new ReturnAttribute("name")));// aggregationAggregationResult ar = s.aggregate("idx", "*", AggregationOptions.defaults().withCursor().load("name"));
Local Cache
Redisson provides JSON Store implementation with local cache.
local cache - so called near cache used to speed up read operations and avoid network roundtrips. It caches JSON Store entries on Redisson side and executes read operations up to 45x faster in comparison with regular implementation. Local cached instances with the same name are 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. It’s recommended to use each local cached instance as a singleton per unique name since it has own state for local cache.
It’s recommended to use a single instance of RLocalCachedJsonStore instance per name for each Redisson client instance. Same LocalCachedJsonStoreOptions object should be used across all instances with the same name.
Follow options can be supplied during object creation:
LocalCachedJsonStoreOptions options = LocalCachedJsonStoreOptions.name("object_name_example")// Defines codec used for key.keyCodec(codec)// Defines codec used for JSON value.valueCodec(codec)// Defines whether to store a cache miss into the local cache.// Default value is false..storeCacheMiss(false);// Defines store mode of cache data.// Follow options are available:// LOCALCACHE - store data in local cache only and use Redis or Valkey only for data update/invalidation.// LOCALCACHE_REDIS - store data in both Redis or Valkey and local cache..storeMode(StoreMode.LOCALCACHE_REDIS)// Defines Cache provider used as local cache store.// Follow options are available:// REDISSON - uses Redisson own implementation// CAFFEINE - uses Caffeine implementation.cacheProvider(CacheProvider.REDISSON)// Defines local cache eviction policy.// Follow options are available:// LFU - Counts how often an item was requested. Those that are used least often are discarded first.// LRU - Discards the least recently used items first// SOFT - Uses soft references, entries are removed by GC// WEAK - Uses weak references, entries are removed by GC// NONE - No eviction.evictionPolicy(EvictionPolicy.NONE)// If cache size is 0 then local cache is unbounded..cacheSize(1000)// Defines strategy for load missed local cache updates after connection failure.//// Follow reconnection strategies are available:// CLEAR - Clear local cache if map instance has been disconnected for a while.// NONE - Default. No reconnection handling.reconnectionStrategy(ReconnectionStrategy.NONE)// Defines local cache synchronization strategy.//// Follow sync strategies are available:// INVALIDATE - Default. Invalidate cache entry across all RLocalCachedJsonStore instances on map entry change// UPDATE - Insert/update cache entry across all RLocalCachedJsonStore instances on map entry change// NONE - No synchronizations on map changes.syncStrategy(SyncStrategy.INVALIDATE)// time to live for each entry in local cache.timeToLive(Duration.ofSeconds(10))// max idle time for each entry in local cache.maxIdle(Duration.ofSeconds(10));// Defines how to listen expired event sent by Redis or Valkey upon this instance deletion//// Follow expiration policies are available:// DONT_SUBSCRIBE - Don't subscribe on expire event// SUBSCRIBE_WITH_KEYEVENT_PATTERN - Subscribe on expire event using `__keyevent@*:expired` pattern// SUBSCRIBE_WITH_KEYSPACE_CHANNEL - Subscribe on expire event using `__keyspace@N__:name` channel.expirationEventPolicy(ExpirationEventPolicy.SUBSCRIBE_WITH_KEYEVENT_PATTERN)
Data write code example:
LocalCachedJsonStoreOptions ops = LocalCachedJsonStoreOptions.name("test").keyCodec(StringCodec.INSTANCE).valueCodec(new JacksonCodec<>(MyObject.class));RLocalCachedJsonStore<String, MyObject> store = redisson.getLocalCachedJsonStore(ops);MyObject t1 = new MyObject();t1.setName("name1");MyObject t2 = new MyObject();t2.setName("name2");Map<String, MyObject> entries = new HashMap<>();entries.put("1", t1);entries.put("2", t2);Map<String, MyObject> entries = new HashMap<>();entries.put("1", t1);entries.put("2", t2);// multiple entries at oncestore.set(entries);// or set entry per callstore.set("1", t1);store.set("2", t2);// with ttlstore.set("1", t1, Duration.ofSeconds(100));// set if not set previouslystore.setIfAbsent("1", t1);// set if entry already existsstore.setIfExists("1", t1);
Data read code example:
LocalCachedJsonStoreOptions ops = LocalCachedJsonStoreOptions.name("test").keyCodec(StringCodec.INSTANCE).valueCodec(new JacksonCodec<>(MyObject.class));RLocalCachedJsonStore<String, MyObject> store = redisson.getLocalCachedJsonStore(ops);// multiple entries at onceMap<String, MyObject> entries = store.get(Set.of("1", "2"));// or read entry per callMyObject value1 = store.get("1");MyObject value2 = store.get("2");
Data deletion code example:
LocalCachedJsonStoreOptions ops = LocalCachedJsonStoreOptions.name("test").keyCodec(StringCodec.INSTANCE).valueCodec(new JacksonCodec<>(MyObject.class));RLocalCachedJsonStore<String, MyObject> store = redisson.getLocalCachedJsonStore(ops);// multiple entries at oncelong deleted = store.delete(Set.of("1", "2"));// or delete entry per callboolean status = store.delete("1");boolean status = store.delete("2");
Set
Redis or Valkey based Set object for Java implements Set interface. This object is thread-safe. Keeps elements uniqueness via element state comparison. Set size limited to 4 294 967 295 elements. Redis or Valkey uses serialized state to check value uniqueness instead of value’s hashCode()/equals() methods.
It has Async, Reactive and RxJava3 interfaces.
RSet<SomeObject> set = redisson.getSet("anySet");set.add(new SomeObject());set.remove(new SomeObject());
RSet object allows to bind a Lock/ReadWriteLock/Semaphore/CountDownLatch object per value:
RSet<MyObject> set = redisson.getSet("anySet");MyObject value = new MyObject();RLock lock = map.getLock(value);lock.lock();try {// process value ...} finally {lock.unlock();}
Eviction and data partitioning
Redisson provides various Set structure implementations with a few important features:
data partitioning - although any Set object is cluster compatible its content isn’t scaled/partitioned across multiple master nodes in cluster. Data partitioning allows to scale available memory, read/write operations and entry eviction process for individual Set instance in cluster.
entry eviction - allows to define time to live parameter per SetCache entry. Redis or Valkey set 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 per unique object name at the moment of getting SetCache instance. If instance isn’t used and has expired entries it should be get again to start the eviction process. This leads to extra Redis or Valkey calls and eviction task per unique SetCache object name.
Entries are cleaned time to time by org.redisson.eviction.EvictionScheduler. By default, it removes 100 expired entries at a time. This can be changed through cleanUpKeysAmount setting. Task launch time tuned automatically and depends on expired entries amount deleted in previous time and varies between 5 second to 30 minutes by default. This time interval can be changed through minCleanUpDelay and maxCleanUpDelay. For example, 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.
advanced entry eviction - improved version of the entry eviction process. Doesn’t use an entry eviction task.
Eviction
Set object with eviction support implements RSetCache, Async, Reactive and RxJava3 interfaces.
Code example:
RSetCache<SomeObject> set = redisson.getSetCache("mySet");// orRMapCache<SomeObject> set = redisson.getClusteredSetCache("mySet");// ttl = 10 minutes,set.add(new SomeObject(), 10, TimeUnit.MINUTES);// if object is not used anymoremap.destroy();
Data partitioning
Map object with data partitioning support implements org.redisson.api.RClusteredSet. Read more details about data partitioning here.
Code example:
RClusteredSet<SomeObject> set = redisson.getClusteredSet("mySet");// orRClusteredSet<SomeObject> set = redisson.getClusteredSetCache("mySet");// ttl = 10 minutes,map.add(new SomeObject(), 10, TimeUnit.MINUTES);
Below is the list of all available Set 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 |
✔️ | ✔️ | ❌ | ✔️ |
Listeners
Redisson allows binding listeners per RSet object. This requires the notify-keyspace-events setting to be enabled on Redis or Valkey side.
| Listener class name | Event description | Valkey or Redisnotify-keyspace-events value |
|---|---|---|
| org.redisson.api.listener.TrackingListener | Element added/removed/updated after read operation | - |
| org.redisson.api.ExpiredObjectListener | RSet object expired |
Ex |
| org.redisson.api.DeletedObjectListener | RSet object deleted |
Eg |
| org.redisson.api.listener.SetAddListener | Element added | Es |
| org.redisson.api.listener.SetRemoveListener | Element removed | Es |
| org.redisson.api.listener.SetRemoveRandomListener | Element randomly removed | Es |
Usage example:
RSet<String> set = redisson.getSet("anySet");int listenerId = set.addListener(new DeletedObjectListener() {@Overridepublic void onDeleted(String name) {// ...}});// ...set.removeListener(listenerId);
SortedSet
Redis or Valkey based distributed SortedSet for Java implements SortedSet interface. This object is 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.
RSortedSet<Integer> set = redisson.getSortedSet("anySet");set.trySetComparator(new MyComparator()); // set object comparatorset.add(3);set.add(1);set.add(2);set.removeAsync(0);set.addAsync(5);
ScoredSortedSet
Redis or Valkey 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 to 4 294 967 295 elements.
RScoredSortedSet<SomeObject> set = redisson.getScoredSortedSet("simple");set.add(0.13, new SomeObject(a, b));set.addAsync(0.251, new SomeObject(c, d));set.add(0.302, new SomeObject(g, d));set.pollFirst();set.pollLast();int index = set.rank(new SomeObject(g, d)); // get element indexDouble score = set.getScore(new SomeObject(g, d)); // get element score
Data partitioning
Although ‘RScoredSortedSet’ object is cluster compatible its content isn’t scaled across multiple master nodes. RScoredSortedSet data partitioning available only in cluster mode and implemented by separate RClusteredScoredSortedSet object. Size is limited by whole 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:
RClusteredScoredSortedSet set = redisson.getClusteredScoredSortedSet("simpleBitset");set.add(1.1, "v1");set.add(1.2, "v2");set.add(1.3, "v3");ScoredEntry<String> s = set.firstEntry();ScoredEntry<String> e = set.pollFirstEntry();
Listeners
Redisson allows binding listeners per RScoredSortedSet object. This requires the notify-keyspace-events setting to be enabled on Redis or Valkey side.
| Listener class name | Event description | Valkey or Redisnotify-keyspace-events value |
|---|---|---|
| org.redisson.api.listener.TrackingListener | Element created/removed/updated after read operation | - |
| org.redisson.api.listener.ScoredSortedSetAddListener | Element created/updated | Ez |
| org.redisson.api.listener.ScoredSortedSetRemoveListener | Element removed | Ez |
| org.redisson.api.ExpiredObjectListener | RScoredSortedSet object expired |
Ex |
| org.redisson.api.DeletedObjectListener | RScoredSortedSet object deleted |
Eg |
Usage example:
RScoredSortedSet<String> set = redisson.getScoredSortedSet("anySet");int listenerId = set.addListener(new DeletedObjectListener() {@Overridepublic void onDeleted(String name) {// ...}});// ...set.removeListener(listenerId);
LexSortedSet
Redis or Valkey 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.
RLexSortedSet set = redisson.getLexSortedSet("simple");set.add("d");set.addAsync("e");set.add("f");set.rangeTail("d", false);set.countHead("e");set.range("d", true, "z", false);
Listeners
Redisson allows binding listeners per RLexSortedSet object. This requires the notify-keyspace-events setting to be enabled on Redis or Valkey side.
| Listener class name | Event description | Valkey or Redisnotify-keyspace-events value |
|---|---|---|
| org.redisson.api.listener.TrackingListener | Element created/removed/updated after read operation | - |
| org.redisson.api.listener.ScoredSortedSetAddListener | Element created/updated | Ez |
| org.redisson.api.listener.ScoredSortedSetRemoveListener | Element removed | Ez |
| org.redisson.api.ExpiredObjectListener | RScoredSortedSet object expired |
Ex |
| org.redisson.api.DeletedObjectListener | RScoredSortedSet object deleted |
Eg |
Usage example:
RLexSortedSet<String> set = redisson.getLexSortedSet("anySet");int listenerId = set.addListener(new DeletedObjectListener() {@Overridepublic void onDeleted(String name) {// ...}});// ...set.removeListener(listenerId);
List
Redis or Valkey 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 to 4 294 967 295 elements.
RList<SomeObject> list = redisson.getList("anyList");list.add(new SomeObject());list.get(0);list.remove(new SomeObject());
Listeners
Redisson allows binding listeners per RList object. This requires the notify-keyspace-events setting to be enabled on Redis or Valkey side.
| Listener class name | Event description | Valkey or Redisnotify-keyspace-events value |
|---|---|---|
| org.redisson.api.listener.TrackingListener | Element created/removed/updated after read operation | - |
| org.redisson.api.listener.ListAddListener | Element created | El |
| org.redisson.api.listener.ListInsertListener | Element inserted | El |
| org.redisson.api.listener.ListSetListener | Element set/updated | El |
| org.redisson.api.listener.ListRemoveListener | Element removed | El |
| org.redisson.api.listener.ListTrimListener | List trimmed | El |
| org.redisson.api.ExpiredObjectListener | RList object expired |
Ex |
| org.redisson.api.DeletedObjectListener | RList object deleted |
Eg |
Usage example:
RList<String> list = redisson.getList("anyList");int listenerId = list.addListener(new DeletedObjectListener() {@Overridepublic void onDeleted(String name) {// ...}});// ...list.removeListener(listenerId);
Queue
Redis or Valkey based distributed unbounded Queue object for Java implements java.util.Queue interface. This object is thread-safe.
It has Async, Reactive and RxJava3 interfaces.
RQueue<SomeObject> queue = redisson.getQueue("anyQueue");queue.add(new SomeObject());SomeObject obj = queue.peek();SomeObject someObj = queue.poll();
Listeners
Redisson allows binding listeners per RQueue object. This requires the notify-keyspace-events setting to be enabled on Redis or Valkey side.
| Listener class name | Event description | Valkey or Redisnotify-keyspace-events value |
|---|---|---|
| org.redisson.api.listener.TrackingListener | Element created/removed/updated after read operation | - |
| org.redisson.api.listener.ListAddListener | Element created | El |
| org.redisson.api.listener.ListRemoveListener | Element removed | El |
| org.redisson.api.ExpiredObjectListener | RQueue object expired |
Ex |
| org.redisson.api.DeletedObjectListener | RQueue object deleted |
Eg |
Usage example:
RQueue<String> queue = redisson.getQueue("anyList");int listenerId = queue.addListener(new DeletedObjectListener() {@Overridepublic void onDeleted(String name) {// ...}});// ...queue.removeListener(listenerId);
Deque
Redis or Valkey based distributed unbounded Deque object for Java implements java.util.Deque interface. This object is thread-safe.
It has Async, Reactive and RxJava3 interfaces.
RDeque<SomeObject> queue = redisson.getDeque("anyDeque");queue.addFirst(new SomeObject());queue.addLast(new SomeObject());SomeObject obj = queue.removeFirst();SomeObject someObj = queue.removeLast();
Listeners
Redisson allows binding listeners per RDeque object. This requires the notify-keyspace-events setting to be enabled on Redis or Valkey side.
| Listener class name | Event description | Valkey or Redisnotify-keyspace-events value |
|---|---|---|
| org.redisson.api.listener.TrackingListener | Element created/removed/updated after read operation | - |
| org.redisson.api.listener.ListAddListener | Element created | El |
| org.redisson.api.listener.ListRemoveListener | Element removed | El |
| org.redisson.api.ExpiredObjectListener | RDeque object expired |
Ex |
| org.redisson.api.DeletedObjectListener | RDeque object deleted |
Eg |
Usage example:
RDeque<String> deque = redisson.getDeque("anyList");int listenerId = deque.addListener(new DeletedObjectListener() {@Overridepublic void onDeleted(String name) {// ...}});// ...deque.removeListener(listenerId);
Blocking Queue
Redis or Valkey based distributed unbounded BlockingQueue object for Java implements java.util.concurrent.BlockingQueue interface. This object is thread-safe.
It has Async, Reactive and RxJava3 interfaces.
RBlockingQueue<SomeObject> queue = redisson.getBlockingQueue("anyQueue");queue.offer(new SomeObject());SomeObject obj = queue.peek();SomeObject obj = queue.poll();SomeObject obj = queue.poll(10, TimeUnit.MINUTES);
poll, pollFromAny, pollLastAndOfferFirstTo and take methods are resubscribed automatically during re-connection to server or failover.
Bounded Blocking Queue
Redis or Valkey based distributed BoundedBlockingQueue for Java implements java.util.concurrent.BlockingQueue interface. BoundedBlockingQueue size limited to 4 294 967 295 elements. This object is thread-safe.
Queue capacity should be defined once by trySetCapacity() method before the usage:
RBoundedBlockingQueue<SomeObject> queue = redisson.getBoundedBlockingQueue("anyQueue");// returns `true` if capacity set successfully and `false` if it already set.queue.trySetCapacity(2);queue.offer(new SomeObject(1));queue.offer(new SomeObject(2));// will be blocked until free space available in queuequeue.put(new SomeObject());SomeObject obj = queue.peek();SomeObject someObj = queue.poll();SomeObject ob = queue.poll(10, TimeUnit.MINUTES);
poll, pollFromAny, pollLastAndOfferFirstTo and take methods will be resubscribed automatically during reconnection to server or failover.
Blocking Deque
Java implementation of Redis or Valkey based BlockingDeque implements java.util.concurrent.BlockingDeque interface. This object is thread-safe.
It has Async, Reactive and RxJava3 interfaces.
RBlockingDeque<Integer> deque = redisson.getBlockingDeque("anyDeque");deque.putFirst(1);deque.putLast(2);Integer firstValue = queue.takeFirst();Integer lastValue = queue.takeLast();Integer firstValue = queue.pollFirst(10, TimeUnit.MINUTES);Integer lastValue = queue.pollLast(3, TimeUnit.MINUTES);
poll, pollFromAny, pollLastAndOfferFirstTo and take methods are resubscribed automatically during re-connection to server or failover.
Delayed Queue
Redis or Valkey 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 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.
RBlockingQueue<String> distinationQueue = ...RDelayedQueue<String> delayedQueue = getDelayedQueue(distinationQueue);// move object to distinationQueue in 10 secondsdelayedQueue.offer("msg1", 10, TimeUnit.SECONDS);// move object to distinationQueue in 1 minutesdelayedQueue.offer("msg2", 1, TimeUnit.MINUTES);// msg1 will appear in 10 secondsdistinationQueue.poll(15, TimeUnit.SECONDS);// msg2 will appear in 2 secondsdistinationQueue.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.
RDelayedQueue<String> delayedQueue = ...delayedQueue.destroy();
Priority Queue
Java implementation of Redis or Valkey based PriorityQueue implements java.util.Queue interface. Elements are ordered according to natural order of Comparable interface or defined Comparator. This object is thread-safe.
Use trySetComparator() method to define own Comparator.
Code example:
public class Entry implements Comparable<Entry>, Serializable {private String key;private Integer value;public Entry(String key, Integer value) {this.key = key;this.value = value;}@Overridepublic int compareTo(Entry o) {return key.compareTo(o.key);}}RPriorityQueue<Entry> queue = redisson.getPriorityQueue("anyQueue");queue.add(new Entry("b", 1));queue.add(new Entry("c", 1));queue.add(new Entry("a", 1));// Entry [a:1]Entry e = queue.poll();// Entry [b:1]Entry e = queue.poll();// Entry [c:1]Entry e = queue.poll();
Priority Deque
Java implementation of Redis or Valkey 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 thread-safe.
Use trySetComparator() method to define own Comparator.
Code example:
public class Entry implements Comparable<Entry>, Serializable {private String key;private Integer value;public Entry(String key, Integer value) {this.key = key;this.value = value;}@Overridepublic int compareTo(Entry o) {return key.compareTo(o.key);}}RPriorityDeque<Entry> queue = redisson.getPriorityDeque("anyQueue");queue.add(new Entry("b", 1));queue.add(new Entry("c", 1));queue.add(new Entry("a", 1));// Entry [a:1]Entry e = queue.pollFirst();// Entry [c:1]Entry e = queue.pollLast();
Priority Blocking Queue
Java implementation of Redis or Valkey 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 thread-safe.
Use trySetComparator() method to define own java.util.Comparator.
poll, pollLastAndOfferFirstTo and take methods are resubscribed automatically during re-connection to a server or failover.
Code example:
public class Entry implements Comparable<Entry>, Serializable {private String key;private Integer value;public Entry(String key, Integer value) {this.key = key;this.value = value;}@Overridepublic int compareTo(Entry o) {return key.compareTo(o.key);}}RPriorityBlockingQueue<Entry> queue = redisson.getPriorityBlockingQueue("anyQueue");queue.add(new Entry("b", 1));queue.add(new Entry("c", 1));queue.add(new Entry("a", 1));// Entry [a:1]Entry e = queue.take();
Priority Blocking Deque
Java implementation of Redis or Valkey 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 thread-safe.
Use trySetComparator() method to define own java.util.Comparator.
poll, pollLastAndOfferFirstTo, take methods are resubscribed automatically during re-connection to Redis or Valkey server or failover.
Code example:
public class Entry implements Comparable<Entry>, Serializable {private String key;private Integer value;public Entry(String key, Integer value) {this.key = key;this.value = value;}@Overridepublic int compareTo(Entry o) {return key.compareTo(o.key);}}RPriorityBlockingDeque<Entry> queue = redisson.getPriorityBlockingDeque("anyQueue");queue.add(new Entry("b", 1));queue.add(new Entry("c", 1));queue.add(new Entry("a", 1));// Entry [a:1]Entry e = queue.takeFirst();// Entry [c:1]Entry e = queue.takeLast();
Stream
Java implementation of Redis or Valkey based Stream object wraps Stream feature. Basically it allows to create Consumers Group which consume data added by Producers. This object is thread-safe.
RStream<String, String> stream = redisson.getStream("test");StreamMessageId sm = stream.add(StreamAddArgs.entry("0", "0"));stream.createGroup("testGroup");StreamId id1 = stream.add(StreamAddArgs.entry("1", "1"));StreamId id2 = stream.add(StreamAddArgs.entry("2", "2"));Map<StreamId, Map<String, String>> group = stream.readGroup("testGroup", "consumer1", StreamReadGroupArgs.neverDelivered());// return entries in pending state after read group method executionMap<StreamMessageId, Map<String, String>> pendingData = stream.pendingRange("testGroup", "consumer1", StreamMessageId.MIN, StreamMessageId.MAX, 100);// transfer ownership of pending messages to a new consumerList<StreamMessageId> transferedIds = stream.fastClaim("testGroup", "consumer2", 1, TimeUnit.MILLISECONDS, id1, id2);// mark pending entries as correctly processedlong amount = stream.ack("testGroup", id1, id2);
Code example of Async interface usage:
RStream<String, String> stream = redisson.getStream("test");RFuture<StreamMessageId> smFuture = stream.addAsync(StreamAddArgs.entry("0", "0"));RFuture<Void> groupFuture = stream.createGroupAsync("testGroup");RFuture<StreamId> id1Future = stream.addAsync(StreamAddArgs.entry("1", "1"));RFuture<StreamId> id2Future = stream.addAsync(StreamAddArgs.entry("2", "2"));RFuture<Map<StreamId, Map<String, String>>> groupResultFuture = stream.readGroupAsync("testGroup", "consumer1", StreamReadGroupArgs.neverDelivered());// return entries in pending state after read group method executionRFuture<Map<StreamMessageId, Map<String, String>>> pendingDataFuture = stream.pendingRangeAsync("testGroup", "consumer1", StreamMessageId.MIN, StreamMessageId.MAX, 100);// transfer ownership of pending messages to a new consumerRFuture<List<StreamMessageId>> transferedIdsFuture = stream.fastClaim("testGroup", "consumer2", 1, TimeUnit.MILLISECONDS, id1, id2);// mark pending entries as correctly processedRFuture<Long> amountFuture = stream.ackAsync("testGroup", id1, id2);amountFuture.whenComplete((res, exception) -> {// ...});
Code example of Reactive interface usage:
RedissonReactiveClient redisson = redissonClient.reactive();RStreamReactive<String, String> stream = redisson.getStream("test");Mono<StreamMessageId> smMono = stream.add(StreamAddArgs.entry("0", "0"));Mono<Void> groupMono = stream.createGroup("testGroup");Mono<StreamId> id1Mono = stream.add(StreamAddArgs.entry("1", "1"));Mono<StreamId> id2Mono = stream.add(StreamAddArgs.entry("2", "2"));Mono<Map<StreamId, Map<String, String>>> groupMono = stream.readGroup("testGroup", "consumer1", StreamReadGroupArgs.neverDelivered());// return entries in pending state after read group method executionMono<Map<StreamMessageId, Map<String, String>>> pendingDataMono = stream.pendingRange("testGroup", "consumer1", StreamMessageId.MIN, StreamMessageId.MAX, 100);// transfer ownership of pending messages to a new consumerMono<List<StreamMessageId>> transferedIdsMono = stream.fastClaim("testGroup", "consumer2", 1, TimeUnit.MILLISECONDS, id1, id2);// mark pending entries as correctly processedMono<Long> amountMono = stream.ack("testGroup", id1, id2);amountMono.doOnNext(res -> {// ...}).subscribe();
Code example of RxJava3 interface usage:
RedissonRxClient redisson = redissonClient.rxJava();RStreamRx<String, String> stream = redisson.getStream("test");Single<StreamMessageId> smRx = stream.add(StreamAddArgs.entry("0", "0"));Completable groupRx = stream.createGroup("testGroup");Single<StreamId> id1Rx = stream.add(StreamAddArgs.entry("1", "1"));Single<StreamId> id2Rx = stream.add(StreamAddArgs.entry("2", "2"));Single<Map<StreamId, Map<String, String>>> groupRx = stream.readGroup("testGroup", "consumer1", StreamReadGroupArgs.neverDelivered());// return entries in pending state after read group method executionSingle<Map<StreamMessageId, Map<String, String>>> pendingDataRx = stream.pendingRange("testGroup", "consumer1", StreamMessageId.MIN, StreamMessageId.MAX, 100);// transfer ownership of pending messages to a new consumerSingle<List<StreamMessageId>> transferedIdsRx = stream.fastClaim("testGroup", "consumer2", 1, TimeUnit.MILLISECONDS, id1, id2);// mark pending entries as correctly processedSingle<Long> amountRx = stream.ack("testGroup", id1, id2);amountRx.doOnSuccess(res -> {// ...}).subscribe();
Listeners
Redisson allows binding listeners per RStream object. This requires the notify-keyspace-events setting to be enabled on Redis or Valkey side.
| Listener class name | Event description | Valkey or Redisnotify-keyspace-events value |
|---|---|---|
| org.redisson.api.listener.TrackingListener | Element added/removed/updated after read operation | - |
| org.redisson.api.ExpiredObjectListener | RStream object expired |
Ex |
| org.redisson.api.DeletedObjectListener | RStream object deleted |
Eg |
| org.redisson.api.listener.StreamAddListener | Element added | Et |
| org.redisson.api.listener.StreamRemoveListener | Element removed | Et |
| org.redisson.api.listener.StreamCreateGroupListener | Group created | Et |
| org.redisson.api.listener.StreamRemoveGroupListener | Group removed | Et |
| org.redisson.api.listener.StreamCreateConsumerListener | Consumer created | Et |
| org.redisson.api.listener.StreamRemoveConsumerListener | Consumer removed | Et |
| org.redisson.api.listener.StreamTrimListener | Stream trimmed | Et |
Usage example:
RStream<String, String> stream = redisson.getStream("anySet");int listenerId = stream.addListener(new DeletedObjectListener() {@Overridepublic void onDeleted(String name) {// ...}});int listenerId = stream.addListener(new StreamAddListener() {@Overridepublic void onAdd(String name) {// ...}});// ...stream.removeListener(listenerId);
Ring Buffer
Java implementation of Redis or Valkey based RingBuffer implements java.util.Queue interface. This structure evicts elements from the head if queue capacity became full. This object is thread-safe.
Should be initialized with capacity size by trySetCapacity() method before usage.
Code example:
RRingBuffer<Integer> buffer = redisson.getRingBuffer("test");// buffer capacity is 4 elementsbuffer.trySetCapacity(4);buffer.add(1);buffer.add(2);buffer.add(3);buffer.add(4);// buffer state is 1, 2, 3, 4buffer.add(5);buffer.add(6);// buffer state is 3, 4, 5, 6
Code example of Async interface usage:
RRingBuffer<Integer> buffer = redisson.getRingBuffer("test");// buffer capacity is 4 elementsRFuture<Boolean> capacityFuture = buffer.trySetCapacityAsync(4);RFuture<Boolean> addFuture = buffer.addAsync(1);RFuture<Boolean> addFuture = buffer.addAsync(2);RFuture<Boolean> addFuture = buffer.addAsync(3);RFuture<Boolean> addFuture = buffer.addAsync(4);// buffer state is 1, 2, 3, 4RFuture<Boolean> addFuture = buffer.addAsync(5);RFuture<Boolean> addFuture = buffer.addAsync(6);// buffer state is 3, 4, 5, 6addFuture.whenComplete((res, exception) -> {// ...});
Code example of Reactive interface usage:
RedissonReactiveClient redisson = redissonClient.reactive();RRingBufferReactive<Integer> buffer = redisson.getRingBuffer("test");// buffer capacity is 4 elementsMono<Boolean> capacityMono = buffer.trySetCapacity(4);Mono<Boolean> addMono = buffer.add(1);Mono<Boolean> addMono = buffer.add(2);Mono<Boolean> addMono = buffer.add(3);Mono<Boolean> addMono = buffer.add(4);// buffer state is 1, 2, 3, 4Mono<Boolean> addMono = buffer.add(5);Mono<Boolean> addMono = buffer.add(6);// buffer state is 3, 4, 5, 6addMono.doOnNext(res -> {// ...}).subscribe();
Code example of RxJava3 interface usage:
RedissonRxClient redisson = redissonClient.rxJava();RRingBufferRx<Integer> buffer = redisson.getRingBuffer("test");// buffer capacity is 4 elementsSingle<Boolean> capacityRx = buffer.trySetCapacity(4);Single<Boolean> addRx = buffer.add(1);Single<Boolean> addRx = buffer.add(2);Single<Boolean> addRx = buffer.add(3);Single<Boolean> addRx = buffer.add(4);// buffer state is 1, 2, 3, 4Single<Boolean> addRx = buffer.add(5);Single<Boolean> addRx = buffer.add(6);// buffer state is 3, 4, 5, 6addRx.doOnSuccess(res -> {// ...}).subscribe();
Listeners
Redisson allows binding listeners per RRingBuffer object. This requires the notify-keyspace-events setting to be enabled on Redis or Valkey side.
| Listener class name | Event description | Valkey or Redisnotify-keyspace-events value |
|---|---|---|
| org.redisson.api.listener.TrackingListener | Element created/removed/updated after read operation | - |
| org.redisson.api.listener.ListAddListener | Element created | El |
| org.redisson.api.listener.ListRemoveListener | Element removed | El |
| org.redisson.api.ExpiredObjectListener | RRingBuffer object expired |
Ex |
| org.redisson.api.DeletedObjectListener | RRingBuffer object deleted |
Eg |
Usage example:
RRingBuffer<String> queue = redisson.getRingBuffer("anyList");int listenerId = queue.addListener(new DeletedObjectListener() {@Overridepublic void onDeleted(String name) {// ...}});// ...queue.removeListener(listenerId);
Transfer Queue
Java implementation of Redis or Valkey 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 thread-safe.
poll and take methods are resubscribed automatically during re-connection to a server or failover.
Code example:
RTransferQueue<String> queue = redisson.getTransferQueue("myCountDownLatch");queue.transfer("data");// or try transfer immediatelyqueue.tryTransfer("data");// or try transfer up to 10 secondsqueue.tryTransfer("data", 10, TimeUnit.SECONDS);// in other thread or JVMqueue.take();// orqueue.poll();
Code example of Async interface usage:
RTransferQueue<String> queue = redisson.getTransferQueue("myCountDownLatch");RFuture<Void> future = queue.transferAsync("data");// or try transfer immediatelyRFuture<Boolean> future = queue.tryTransferAsync("data");// or try transfer up to 10 secondsRFuture<Boolean> future = queue.tryTransferAsync("data", 10, TimeUnit.SECONDS);// in other thread or JVMRFuture<String> future = queue.takeAsync();// orRFuture<String> future = queue.pollAsync();future.whenComplete((res, exception) -> {// ...});
Code example of Reactive interface usage:
RedissonReactiveClient redisson = redissonClient.reactive();RTransferQueueReactive<String> queue = redisson.getTransferQueue("myCountDownLatch");Mono<Void> mono = queue.transfer("data");// or try transfer immediatelyMono<Boolean> mono = queue.tryTransfer("data");// or try transfer up to 10 secondsMono<Boolean> mono = queue.tryTransfer("data", 10, TimeUnit.SECONDS);// in other thread or JVMMono<String> mono = queue.take();// orMono<String> mono = queue.poll();mono.doOnNext(res -> {// ...}).subscribe();
Code example of RxJava3 interface usage:
RedissonRxClient redisson = redissonClient.rxJava();RTransferQueueRx<String> queue = redisson.getTransferQueue("myCountDownLatch");Completable res = queue.transfer("data");// or try transfer immediatelySingle<Boolean> resRx = queue.tryTransfer("data");// or try transfer up to 10 secondsSingle<Boolean> resRx = queue.tryTransfer("data", 10, TimeUnit.SECONDS);// in other thread or JVMSingle<String> resRx = queue.take();// orMaybe<String> resRx = queue.poll();resRx.doOnSuccess(res -> {// ...}).subscribe();
Time Series
Java implementation of Redis or Valkey 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 thread-safe.
Code example:
RTimeSeries<String> ts = redisson.getTimeSeries("myTimeSeries");ts.add(201908110501, "10%");ts.add(201908110502, "30%");ts.add(201908110504, "10%");ts.add(201908110508, "75%");// entry time-to-live is 10 hoursts.add(201908110510, "85%", 10, TimeUnit.HOURS);ts.add(201908110510, "95%", 10, TimeUnit.HOURS);String value = ts.get(201908110508);ts.remove(201908110508);Collection<String> values = ts.pollFirst(2);Collection<String> range = ts.range(201908110501, 201908110508);
Code example of Async interface usage:
RTimeSeries<String> ts = redisson.getTimeSeries("myTimeSeries");RFuture<Void> future = ts.addAsync(201908110501, "10%");RFuture<Void> future = ts.addAsync(201908110502, "30%");RFuture<Void> future = ts.addAsync(201908110504, "10%");RFuture<Void> future = ts.addAsync(201908110508, "75%");// entry time-to-live is 10 hoursRFuture<Void> future = ts.addAsync(201908110510, "85%", 10, TimeUnit.HOURS);RFuture<Void> future = ts.addAsync(201908110510, "95%", 10, TimeUnit.HOURS);RFuture<String> future = ts.getAsync(201908110508);RFuture<Boolean> future = ts.removeAsync(201908110508);RFuture<Collection<String>> future = t.pollFirstAsync(2);RFuture<Collection<String>> future = t.rangeAsync(201908110501, 201908110508);future.whenComplete((res, exception) -> {// ...});
Code example of Reactive interface usage:
RedissonReactiveClient redisson = redissonClient.reactive();RTimeSeriesReactive<String> ts = redisson.getTimeSeries("myTimeSeries");Mono<Void> mono = ts.add(201908110501, "10%");Mono<Void> mono = ts.add(201908110502, "30%");Mono<Void> mono = ts.add(201908110504, "10%");Mono<Void> mono = ts.add(201908110508, "75%");// entry time-to-live is 10 hoursMono<Void> mono = ts.add(201908110510, "85%", 10, TimeUnit.HOURS);Mono<Void> mono = ts.add(201908110510, "95%", 10, TimeUnit.HOURS);Mono<String> mono = ts.get(201908110508);Mono<Boolean> mono = ts.remove(201908110508);Mono<Collection<String>> mono = ts.pollFirst(2);Mono<Collection<String>> mono = ts.range(201908110501, 201908110508);mono.doOnNext(res -> {// ...}).subscribe();
Code example of RxJava3 interface usage:
RedissonRxClient redisson = redissonClient.rxJava();RTimeSeriesRx<String> ts = redisson.getTimeSeries("myTimeSeries");Completable rx = ts.add(201908110501, "10%");Completable rx = ts.add(201908110502, "30%");Completable rx = ts.add(201908110504, "10%");Completable rx = ts.add(201908110508, "75%");// entry time-to-live is 10 hoursCompletable rx = ts.add(201908110510, "85%", 10, TimeUnit.HOURS);Completable rx = ts.add(201908110510, "95%", 10, TimeUnit.HOURS);Maybe<String> rx = ts.get(201908110508);Single<Boolean> rx = ts.remove(201908110508);Single<Collection<String>> rx = ts.pollFirst(2);Single<Collection<String>> rx = ts.range(201908110501, 201908110508);rx.doOnSuccess(res -> {// ...}).subscribe();
Listeners
Redisson allows binding listeners per RTimeSeries object. This requires the notify-keyspace-events setting to be enabled on Redis or Valkey side.
| Listener class name | Event description | Valkey or Redisnotify-keyspace-events value |
|---|---|---|
| org.redisson.api.listener.TrackingListener | Element created/removed/updated after read operation | - |
| org.redisson.api.listener.ScoredSortedSetAddListener | Element created/updated | Ez |
| org.redisson.api.listener.ScoredSortedSetRemoveListener | Element removed | Ez |
| org.redisson.api.ExpiredObjectListener | RTimeSeries object expired |
Ex |
| org.redisson.api.DeletedObjectListener | RTimeSeries object deleted |
Eg |
Usage example:
RTimeSeries<String> set = redisson.getTimeSeries("obj");int listenerId = set.addListener(new DeletedObjectListener() {@Overridepublic void onDeleted(String name) {// ...}});// ...set.removeListener(listenerId);
