Reputation: 1191
I have a question related to synchronization and concurrency in Java.
So I have a method, like this:
private boolean loadData(final Integer fundId, List<Trade> trades) {
synchronized (fundId) {
// do lots of things here and finally load the trades into DB
}
}
Before I made this change, the complete method loadData
was synchronized private synchronized boolean loadData
. However, my requirement is such that if, lets say, fundId - 1 is processing, then I can allow concurrent processing of any other fundId other than 1.
So, the above code also won't work because the lock would be on the Integer object, hence no other fundId can be concurrently processed. Is there a way to achieve concurrent processing based on the method parameter ?
Upvotes: 1
Views: 512
Reputation: 1157
You need to create an entry in a ConcurrentHashMap
for each value of fundId in order to lock it.
static Map<Integer, Object> locks = new ConcurrentHashMap<>();
private boolean loadData(final Integer fundId, List<Trade> trades){
locks.computeIfAbsent(fundId, k-> { /* your actual job */ return null; });
}
}
Hope that helps !
Upvotes: 1
Reputation: 552
You can achieve that in several ways:
loadData()
is called FundLoader
you can have a Map<Integer, FundLoader> fundLoaders
and each FundLoader is responsible to load the trades for given fundId. The synchronization will be again on method level for loadData
private final Map<Integer, Object> fundLocks = new HashMap<>();
private final Map<Integer, AtomicInteger> fundsWaitingForLock = new HashMap<>();
private boolean loadData(final Integer fundId, final List<String> trades) {
Object lock;
synchronized (fundLocks) {
lock = fundLocks.computeIfAbsent(fundId, id -> new Object());
fundsWaitingForLock.computeIfAbsent(fundId, id -> new AtomicInteger()).incrementAndGet();
}
synchronized(lock) {
try {
// do lots of things here and finally load the trades into DB
return true;
} finally {
synchronized (fundLocks) {
if (fundsWaitingForLock.get(fundId).decrementAndGet() == 0) {
fundLocks.remove(fundId);
fundsWaitingForLock.remove(fundId);
}
}
}
}
}
private boolean loadData(final Lock fundIdLock, final List<String> trades) {
fundIdLock.lock();
try {
// do lots of things here and finally load the trades into DB
} finally {
fundIdLock.unlock();
}
return true;
}
Upvotes: -1
Reputation: 51632
The function, as it is written, will synchronize on the object fundId
, not on Integer
. So, it will block if you call the same function from another thread with the same fundId
instance. It will not, however, synchronize if you call it with other fundId
instances, regardless of the value.
If you need to synchronize based on a value, you can use a shared set of integers (i.e. fundId). Synchronize on the set, and attempt to insert the integer. If it is already in there, someone else is processing that value, so you wait. If it is not there, then you insert it, unlock, process, lock again, remove the value, and signal.
Upvotes: 1