首页 > 解决方案 > 我可以通过参数同步方法吗

问题描述

我可以通过参数同步方法吗?

例如 - 我让人使用某种方法,我想为人做一些操作,但是如果很少有线程为同一个人调用这个方法,我想一个一个地做。

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

如何只为同一个id一一调用dsomethingelse(id,person)?但我希望可以多线程调用不同 id-s 的这段代码

我写了这段代码,但这里可能有问题,或者有更好的地方。

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

例子:

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

private void dosomething(Long id, Person person) {
     latch.latch(
        id,
        currentId -> { dosomethingelse(currentId, person); }
     );
}

标签: javamultithreadingsynchronization

解决方案


使用 a 的问题CountdownLatch是您不能“增加”计数,因此您需要在使用现有锁存器时替换它,这会使代码复杂化。

您可以改为使用带有Semaphore一个许可证的许可证,这将允许您以更简单的方式做同样的事情。

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

推荐阅读