Clustered Locks with Embedded Infinispan

What You Will Learn

How to use Infinispan clustered locks to synchronize concurrent operations across a cluster of embedded nodes using the asynchronous ClusteredLock API.

Prerequisites

  • Java 17+

Step 1: Add Dependencies

Add the Infinispan core and clustered lock modules to your pom.xml:

<dependency>
   <groupId>org.infinispan</groupId>
   <artifactId>infinispan-core</artifactId>
</dependency>
<dependency>
   <groupId>org.infinispan</groupId>
   <artifactId>infinispan-clustered-lock</artifactId>
</dependency>

Step 2: Create a Clustered Lock Manager

Start a clustered cache manager and obtain a ClusteredLockManager from it:

      // Setup up a clustered cache manager
      GlobalConfigurationBuilder global = GlobalConfigurationBuilder.defaultClusteredBuilder();

      // Initialize 1 cache managers
      cacheManager = new DefaultCacheManager(global.build());

      // Initialize the clustered lock manager from the cache manager
      clusteredLockManager = EmbeddedClusteredLockManagerFactory.from(cacheManager);

Step 3: Define and Use a Clustered Lock

Define a named lock and acquire it asynchronously. The lock is non-reentrant by default:

      // Define a lock. By default, this lock is non reentrant
      clusteredLockManager.defineLock("lock");

      // Get a lock interface from each node
      lock = clusteredLockManager.get("lock");

Multiple concurrent tryLock calls can be coordinated with CompletableFuture.allOf to wait for all operations to complete:

      // Acquire and release the lock 3 times
      CompletableFuture<Boolean> call1 = lock.tryLock(1, TimeUnit.SECONDS).whenComplete((r, ex) -> {
         if (r) {
            System.out.println("lock is acquired by the call 1");
            lock.unlock().whenComplete((nil, ex2) -> {
               System.out.println("lock is released by the call 1");
               counter.incrementAndGet();
            });
         }
      });

      CompletableFuture<Boolean> call2 = lock.tryLock(1, TimeUnit.SECONDS).whenComplete((r, ex) -> {
         if (r) {
            System.out.println("lock is acquired by the call 2");
            lock.unlock().whenComplete((nil, ex2) -> {
               System.out.println("lock is released by the call 2");
               counter.incrementAndGet();
            });
         }
      });

      CompletableFuture<Boolean> call3 = lock.tryLock(1, TimeUnit.SECONDS).whenComplete((r, ex) -> {
         if (r) {
            System.out.println("lock is acquired by the call 3");
            lock.unlock().whenComplete((nil, ex2) -> {
               System.out.println("lock is released by the call 3");
               counter.incrementAndGet();
            });
         }
      });

      CompletableFuture.allOf(call1, call2, call3).whenComplete((r, ex) -> {
         // Print the value of the counter
         System.out.println("Value of the counter is " + counter.get());
      }).get(10, TimeUnit.SECONDS);

Step 4: Run the Tutorial

mvn package exec:java

The output shows each lock acquisition and release in sequence, with a final counter value reflecting the number of successful lock operations.

What’s Next