Java synchronized method around parameter value

无人久伴 提交于 2019-12-30 06:44:20

问题


Consider the following method:

public void upsert(int customerId, int somethingElse) {
  // some code which is prone to race conditions    
}

I want to protect this method from race conditions, but this can only occur if two threads with the same customerId are calling it at the same time. If I make the whole method synchronized it will reduce the efficiency and it's not really needed. What I really want is to synchronize it around the customerId. Is this possible somehow with Java? Are there any built-in tools for that or I'd need a Map of Integers to use as locks?

Also feel free to advice if you think I'm doing something wrong here :)

Thanks!


回答1:


The concept you're looking for is called segmented locking or striped locking. It is too wasteful to have a separate lock for each customer (locks are quite heavyweight). Instead you want to partition your customer ID space into a reasonable number of partitions, matching the desired degree of parallelism. Typically 8-16 would be enough, but this depends on the amount of work the method does.

This outlines a simple approach:

private final Object[] locks = new Object[8];

synchronized (locks[customerId % locks.length]) {
    ...implementation...
}



回答2:


    private static final Set<Integer> lockedIds = new HashSet<>();

    private void lock(Integer id) throws InterruptedException {
        synchronized (lockedIds) {
            while (!lockedIds.add(id)) {
                lockedIds.wait();
            }
        }
    }

    private void unlock(Integer id) {
        synchronized (lockedIds) {
            lockedIds.remove(id);
            lockedIds.notifyAll();
        }
    }

    public void upsert(int customerId) throws InterruptedException {
        try {
            lock(customerId);

            //Put your code here.
            //For different ids it is executed in parallel.
            //For equal ids it is executed synchronously.

        } finally {
            unlock(customerId);
        }
    }
  • id can be not only an 'Integer' but any class with correctly overridden 'equals' and 'hashCode' methods.
  • try-finally - is very important - you must guarantee to unlock waiting threads after your operation even if your operation threw exception.
  • It will not work if your back-end is distributed across multiple servers/JVMs.


来源:https://stackoverflow.com/questions/39490900/java-synchronized-method-around-parameter-value

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!