Wiki

Clone wiki

atlassian-util-concurrent / ManagedLock

A ManagedLock is an encapsulation of a lock that means the locking (and correct unlocking) is handled for you. It is most helpful in cases where the locks may be managed for you (in a for instance an adaptive striped locking service).

Usage

ManagedLock lock = lockService.get(key);
return lock.withLock(new Supplier<String>() {
  public String get() {
    return "this is the " + counter.get() + "th call!";
  }
});

There are also versions that will accept a Callable (which therefore declares that it throws Exception) and Runnable (which therefore returns void).

There is also the sub-interface ManagedLock.ReadWrite for dealing with read/write locking.

ManagedLocks

This class has most of the factory methods you should need to create and manage instances of ManagedLock. The simplest (creating one that wraps a ReentrantLock) is:

ManagedLock lock = ManagedLocks.newManagedLock();

If you need to supply a Lock that was created somewhere else, is a specialised implementation or is needed for tracking/monitoring:

ManagedLock lock = ManagedLocks.manage(myLock);{code}

Lock striping

You can also create factories that manage locks for you based on some input. These are useful for striping, and are optimised to keep as low a memory profile as possible by using weak references internally.

The factories are of the shape Function<T, ManagedLock> where T is some value* we base our stripe on.

If say we want to stripe based on an entity's Long id, we might have a lock factory:

Function<Long, ManagedLock> lockFactory = ManagedLocks.weakManagedLockFactory();

// protect update per entity
return lockFactory.get(entity.id()).withLock(new Supplier<Entity>() {
  public Entity get() {
    return service.update(entity);
  }
});

If a Lock is not used anymore then it becomes eligible for GC.

To restrict the maximum number of locks used, or to make the usage easier, you can pass in a Function that extracts the value from the input:

// simple extract function
Function<Entity, ManagedLock> lockFactory = 
  ManagedLocks.weakManagedLockFactory(
    new Function<Entity, Long>() {
      public Long get(Entity entity) {
        return entity.id();
      }
    }
  );

// keep the max locks to 16
Function<Entity, ManagedLock> lockFactory = 
  ManagedLocks.weakManagedLockFactory(
    new Function<Entity, Integer>() {
      public Integer get(Entity entity) {
        return (int) (entity.id() % 16);
      }
    }
  );
  • By value we mean an immutable object that correctly implements the hashcode/equals contract.

src/main/java/com/atlassian/util/concurrent/ManagedLock.java src/main/java/com/atlassian/util/concurrent/ManagedLocks.java

Updated