Skip to content

8. Distributed locks and synchronizers

Nikita Koksharov edited this page Mar 28, 2019 · 27 revisions

8.1. Lock

Redis based distributed reentrant Lock object for Java and implements java.util.concurrent.locks.Lock interface. It has Async, Reactive and RxJava2 interfaces.

RLock lock = redisson.getLock("anyLock");
// Most familiar locking method
lock.lock();

If Redisson instance which acquired lock crashes then such lock could hang forever in acquired state. To avoid this Redisson maintains lock watchdog, it prolongs lock expiration while lock holder Redisson instance is alive. By default lock watchdog timeout is 30 seconds and can be changed through Config.lockWatchdogTimeout setting.

Also Redisson allow to specify leaseTime parameter during lock acquisition. After specified time interval locked lock will be released automatically.

// Acquire lock and release it automatically after 10 seconds
// if unlock method hasn't been invoked
lock.lock(10, TimeUnit.SECONDS);

// Wait for 100 seconds and automatically unlock it after 10 seconds
boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
if (res) {
   try {
     ...
   } finally {
       lock.unlock();
   }
}

Redisson also provides an asynchronous methods for Lock object:

RLock lock = redisson.getLock("anyLock");
lock.lockAsync();
lock.lockAsync(10, TimeUnit.SECONDS);
Future<Boolean> res = lock.tryLockAsync(100, 10, TimeUnit.SECONDS);

RLock objects behave according java Lock specification. It means only lock owner thread can unlock it otherwise IllegalMonitorStateException would be thrown. But if you still need such scenario use RSemaphore object.

8.2. Fair Lock

Redis based distributed reentrant fair Lock object for Java implements java.util.concurrent.locks.Lock interface. It has Async, Reactive and RxJava2 interfaces.

It guarantees that threads will acquire it in is same order they requested it. All waiting threads are queued and if some thread has died then Redisson waits its return for 5 seconds. For example, if 5 threads are died for some reason then delay will be 25 seconds.

RLock fairLock = redisson.getFairLock("anyLock");
// Most familiar locking method
fairLock.lock();

If Redis node which stores lock state crashes and lock has been already acquired then it could hang forever. To avoid this Redisson maintains lock watchdog, it prolongs lock expiration while lock holder Redisson instance is alive. By default lock watchdog timeout is 30 seconds and can be changed through Config.lockWatchdogTimeout setting.

Also Redisson allow to specify leaseTime parameter during lock acquisition. After specified time interval locked lock will be released automatically.

// Acquire lock and release it automatically after 10 seconds
// if unlock method hasn't been invoked
fairLock.lock(10, TimeUnit.SECONDS);

// Wait for 100 seconds and automatically unlock it after 10 seconds
boolean res = fairLock.tryLock(100, 10, TimeUnit.SECONDS);
...
fairLock.unlock();

Redisson also provides an asynchronous methods for fair Lock object:

RLock fairLock = redisson.getFairLock("anyLock");
fairLock.lockAsync();
fairLock.lockAsync(10, TimeUnit.SECONDS);
Future<Boolean> res = fairLock.tryLockAsync(100, 10, TimeUnit.SECONDS);

8.3. MultiLock

Redis based distributed RedissonMultiLock object for Java groups multiple RLock objects and handles them as one lock. Each RLock object may belong to different Redisson instances.

RLock lock1 = redissonInstance1.getLock("lock1");
RLock lock2 = redissonInstance2.getLock("lock2");
RLock lock3 = redissonInstance3.getLock("lock3");

RedissonMultiLock lock = anyRedissonInstance.getMultiLock(lock1, lock2, lock3);
// locks: lock1 lock2 lock3
lock.lock();
...
lock.unlock();

If Redis nodes stored lock state crash and multiple locks have been already acquired then they could hang forever. To avoid this Redisson maintains lock watchdog, it prolongs each lock expiration while lock holder Redisson instance is alive. By default lock watchdog timeout is 30 seconds and can be changed through Config.lockWatchdogTimeout setting.

Also Redisson allow to specify leaseTime parameter during lock acquisition. After specified time interval all locked locks will be released automatically.

RedissonMultiLock lock = anyRedissonInstance.getMultiLock(lock1, lock2, lock3);
// Acquire lock1, lock2, lock3 and release it automatically after 10 seconds
// if unlock method hasn't been invoked
lock.lock(10, TimeUnit.SECONDS);

// Wait for 100 seconds and automatically unlock it after 10 seconds
boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
...
lock.unlock();

8.4. RedLock

Redis based distributed RedissonRedLock object for Java implements Redlock locking algorithm. It groups multiple RLock objects and handles them as one lock. Each RLock object may belong to different Redisson instances.

RLock lock1 = redissonInstance1.getLock("lock1");
RLock lock2 = redissonInstance2.getLock("lock2");
RLock lock3 = redissonInstance3.getLock("lock3");

RedissonRedLock lock = anyRedissonInstance.getRedLock(lock1, lock2, lock3);
// locks: lock1 lock2 lock3
lock.lock();
...
lock.unlock();

If Redis nodes stored lock state crash and multiple locks have been already acquired then they could hang forever. To avoid this Redisson maintains lock watchdog, it prolongs each lock expiration while lock holder Redisson instance is alive. By default lock watchdog timeout is 30 seconds and can be changed through Config.lockWatchdogTimeout setting.

Also Redisson allow to specify leaseTime parameter during lock acquisition. After specified time interval all locked locks will be released automatically.

RedissonRedLock lock = anyRedissonInstance.getRedLock(lock1, lock2, lock3);
// Acquire lock1, lock2, lock3 and release it automatically after 10 seconds
// if unlock method hasn't been invoked
lock.lock(10, TimeUnit.SECONDS);

// Wait for 100 seconds and automatically unlock it after 10 seconds
boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
...
lock.unlock();

8.5. ReadWriteLock

Redis based distributed reentrant ReadWriteLock object for Java implements java.util.concurrent.locks.ReadWriteLock interface. Both Read and Write locks implements RLock interface.

Multiple ReadLock owners and only one WriteLock owner are allowed.

RReadWriteLock rwlock = redisson.getReadWriteLock("anyRWLock");
// Most familiar locking method
rwlock.readLock().lock();
// or
rwlock.writeLock().lock();

If Redis node stored lock state crashes and lock has been already acquired then it could hang forever. To avoid this Redisson maintains lock watchdog, it prolongs lock expiration while lock holder Redisson instance is alive. By default lock watchdog timeout is 30 seconds and can be changed through Config.lockWatchdogTimeout setting.

Also Redisson allow to specify leaseTime parameter during lock acquisition. After specified time interval locked lock will be released automatically.

// Acquire lock and release it automatically after 10 seconds
// if unlock method not invoked
rwlock.readLock().lock(10, TimeUnit.SECONDS);
// or
rwlock.writeLock().lock(10, TimeUnit.SECONDS);

// Wait for 100 seconds and automatically unlock it after 10 seconds
boolean res = rwlock.readLock().tryLock(100, 10, TimeUnit.SECONDS);
// or
boolean res = rwlock.writeLock().tryLock(100, 10, TimeUnit.SECONDS);
...
lock.unlock();

8.6. Semaphore

Redis based distributed Semaphore object for Java similar to java.util.concurrent.Semaphore object. It has Async, Reactive and RxJava2 interfaces.

RSemaphore semaphore = redisson.getSemaphore("semaphore");
semaphore.acquire();
//or
semaphore.acquireAsync();
semaphore.acquire(23);
semaphore.tryAcquire();
//or
semaphore.tryAcquireAsync();
semaphore.tryAcquire(23, TimeUnit.SECONDS);
//or
semaphore.tryAcquireAsync(23, TimeUnit.SECONDS);
semaphore.release(10);
semaphore.release();
//or
semaphore.releaseAsync();

8.7. PermitExpirableSemaphore

Redis based distributed Semaphore object for Java with lease time parameter support for each acquired permit. Each permit identified by own id and could be released only using its id. It has Async, Reactive and RxJava2 interfaces.

RPermitExpirableSemaphore semaphore = redisson.getPermitExpirableSemaphore("mySemaphore");
String permitId = semaphore.acquire();
// acquire permit with lease time = 2 seconds
String permitId = semaphore.acquire(2, TimeUnit.SECONDS);
// ...
semaphore.release(permitId);

8.8. CountDownLatch

Redis based distributed CountDownLatch object for Java has structure similar to java.util.concurrent.CountDownLatch object.

RCountDownLatch latch = redisson.getCountDownLatch("anyCountDownLatch");
latch.trySetCount(1);
latch.await();

// in other thread or other JVM
RCountDownLatch latch = redisson.getCountDownLatch("anyCountDownLatch");
latch.countDown();
You can’t perform that action at this time.