Redis-Based Distributed Java Semaphores With Redisson
We take a look under the hood of this interesting open source database and see how ti uses Java methods to make distributed semaphores possible.
Join the DZone community and get the full member experience.
Join For Free
A semaphore is an entity that controls how many processes can access the same resource concurrently. Locks can be thought of as a special type of semaphore with an upper limit of 1 process.
Semaphores allow access to a resource by giving permits to a process. The process must first acquire a permit, and then release it once it is no longer needed. The semaphor maintains an internal counter to keep track of how many permits remain.
Because semaphores are a crucial part of distributed and parallel computing, it’s no surprise that you can build semaphores in Redis. However, building a correctly-working Redis-based semaphore on Java all by yourself can be difficult and time-consuming (as you’ll see if you check out that link).
The good news is that you can use Redisson: a framework for distributed programming with Redis and Java that already contains implementations of semaphores and related concepts (such as the CountDownLatch).
Below, we’ll discuss three essential objects for distributed programming in Redis—RSemaphore, RPermitExpirableSemaphore, and RCountDownLatch—and the right situation to use each one.
Semaphore
The RSemaphore object in Redisson is similar to the java.util.concurrent.Semaphore class in plain Java. The acquire()
method is used to acquire a permit from the semaphore, and the release()
method is used to release a permit that is no longer needed.
In the event that no permit is available, the acquire()
method blocks the thread until one is available or the thread is interrupted. The tryAcquire()
method attempts to acquire a permit for a specified amount of time (e.g. 23 seconds in the example code below):
RSemaphore semaphore = redisson.getSemaphore("semaphore");
semaphore.acquire();
//try to acquire in 23 seconds
semaphore.tryAcquire(23, TimeUnit.SECONDS);
// ...
semaphore.release();
The RSemaphore
object comes with three different interfaces that you can use: Async, Reactive, and RxJava2.
PermitExpirableSemaphore
The RPermitExpirableSemaphore object in Redisson is used for semaphores whose permits can be acquired with an (optional) time limit. Each permit is identified by a unique ID and can only be released using this ID.
In the example code below, we attempt to acquire two permits from the semaphore: one with no time limit, and one with a time limit of 2 seconds.
RPermitExpirableSemaphore semaphore = redisson.getPermitExpirableSemaphore("mySemaphore");
String permitId = semaphore.acquire();
// acquire permit with a lease time of 2 seconds
String permitId = semaphore.acquire(2, TimeUnit.SECONDS);
// ...
semaphore.release(permitId);
The RPermitExpirableSemaphore object comes with three different interfaces that you can use: Async, Reactive, and RxJava2.
CountDownLatch
The RCountDownLatch
object in Redisson is similar to the java.util.concurrent.CountDownLatch class in plain Java. In Java, a CountDownLatch
is used to ensure that a thread waits until another thread or threads complete a set of operations. This is slightly different from the purpose of a Semaphore, which is used to control the number of threads that are concurrently accessing a resource.
In this example code, the first thread waits for another thread to finish using the await()
method:
RCountDownLatch latch = redisson.getCountDownLatch("anyCountDownLatch");
latch.trySetCount(1);
// ...
latch.await();
Meanwhile, in another thread or another Java virtual machine uses the same Redis setup through Redisson, the countDown()
method is used to decrement the counter of the CountDownLatch
:
RCountDownLatch latch = redisson.getCountDownLatch("anyCountDownLatch");
latch.countDown();
After the countDown()
method is called, the first thread should be able to access the resource.
Opinions expressed by DZone contributors are their own.
Comments