Search code examples
javarestsynchronizationsynchronized

Java synchronization depending on method parameter


how can I provide synchronization upon method parameter values?

All method calls using the 'same' parameter value A should be synchronized. A method call with a different parameter value e.g. B can access, even when calls with A are already waiting. The next concurrent call for B must wait also for the first B to be released.

My use case: I want to synchronize the access to JPA entities on ID level but want to avoid pessimistic locking because I need kind of a queue. The 'key' for locking is intended to be the entity ID - which is in fact of the type Java Long.

protected void entityLockedAccess(SomeEntity myEntity) {
    //getId() returns different Long objects so the lock does not work
    synchronized (myEntity.getId()) {
        //the critical section ...
    }
}

I read about lock objects but I am not sure how they would suit in my case. On the top level I want to manage a specific REST call to my application which executes critical code.

Thanks, Chris


Solution

  • As far as I understood you basically want a different, unique lock for each of your SomeEntity IDs.

    You could realize this with a Map<Integer, Object>.

    You simply map each ID to an object. Should there already be an object, you reuse it. This could look something like this:

    static Map<Integer, Object> locks = new ConcurrentHashMap<>();
    
    public static void main(String[] args)
    {
        int i1 = 1;
        int i2 = 2;
    
        foo(i1);
        foo(i1);
        foo(i2);
    }
    
    public static void foo(int o)
    {
        synchronized (locks.computeIfAbsent(o, k -> new Object()))
        {
            // computation
        }
    }
    

    This will create 2 lock objects in the map as the object for i1 is reused in the second foo(i1) call.