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.
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 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);
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
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
RCountDownLatch latch = redisson.getCountDownLatch("anyCountDownLatch"); latch.countDown();
countDown() method is called, the first thread should be able to access the resource.
Opinions expressed by DZone contributors are their own.