omickron omickron - 6 months ago 16
Java Question

Is trere a simplier way to have concurrentmap with locks?

I have a requireement to have locks in some function per entity ID.

private final ConcurrentMap<Long, Lock> idLocks = Maps.newConcurrentMap();

public void doSmth(Long id){
ReentrantLock newLock = new ReentrantLock();
Lock lock = prLocks.putIfAbsent( id, newLock ); //returns null for first run for this id
if (null == lock) { //have to do null checking
lock = newLock;
}
if (lock.tryLock()){
try {
//some code here
} finally {
lock.unlock();
}
}
}


Is there a way to run
Lock lock = returnExistingOrPutAndReturnNew( id, newLock );
to get rid of null checking?

Answer

No, there is no such method in ConcurrentMap, but you can use guava LoadingCache:

private final LoadingCache<Long, Lock> idLocks = CacheBuilder.newBuilder()
       .build(
             new CacheLoader<Long, Lock>() {
                   public Lock load(Long id) throws AnyException {
                       return new ReentrantLock();
                   }
             });

public void doSmth(Long id){
     Lock lock = prLocks.get(id); //always return not-null Lock
     if (lock.tryLock()){
          try {
             //some code here
          } finally {
             lock.unlock();
          }
     }
 }

UPDATE:

In java 8 you can use Map#computeIfAbsent method:

public void doSmth(Long id){
    Lock lock = prLocks.computeIfAbsent(id, key -> new ReentrantLock());
    if (lock.tryLock()){
        try {
            //some code here
        } finally {
            lock.unlock();
        }
    }
}
Comments