问题
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