Search code examples
javaconcurrencyjava.util.concurrent

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?


Solution

  • 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();
            }
        }
    }