Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I synchronize method by parameter

Can I synchronize method by parameter?

For example - I get person to some method and I want to do some operation for person, but if few thread call this method for the same person I want to do it one by one.

private void dosomething(Long id, Person person) {
    dosomethingelse(id, person);
}

How to call dosomethingelse (id, person) only for the same id one by one? but I want that this code for different id-s can be called multithreadly

I wrote this code, but maybe something wrong here or something can be better.

public static class LatchByValue <T> {
    public void latch(T value, ConsumerWithException<T> consummer) throws Exception {
        CountDownLatch latch = new CountDownLatch(1);
        try {
            CountDownLatch previousLatch = null;
            // we are checking if another thread is already calling this method with the same id
            // if sync has CountDownLatch so another thread is already calling this method 
            // or we put our latch and go on
            while ((previousLatch = sync.putIfAbsent(value, latch)) != null) {
                try {
                    // we are waiting for another thread, we are waiting for all threads that put their latch before our thread
                    previousLatch.await();
                } catch (InterruptedException e) {
                    return;
                }
            }
            consummer.accept(value);
        } finally {
            latch.countDown();
            sync.remove(value, latch);
        } 
    }
    private ConcurrentHashMap<T, CountDownLatch> sync = new ConcurrentHashMap<>();
}

Example:

LatchByValue<Long> latch = new LatchByValue<>();

private void dosomething(Long id, Person person) {
     latch.latch(
        id,
        currentId -> { dosomethingelse(currentId, person); }
     );
}
like image 432
Sergey Orlov Avatar asked Apr 08 '26 23:04

Sergey Orlov


1 Answers

Problem with using a CountdownLatch is that you can't "increment" the count so you need to replace the existing latch when it's been used, which complicates the code.

You could instead use a Semaphore with one permit which would allow you to do the same thing but in a simpler way.

Semaphore s = sync.computeIfAbsent(value, x -> new Semaphore(1, true));
s.acquire(); //this blocks and throws InterruptedException, which you need to handle
try {
  consummer.accept(value);
} finally {
  s.release();
}
like image 62
assylias Avatar answered Apr 11 '26 13:04

assylias



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!