[Update]: Added solutions using a WeakHashMap-Cache to get the cleaning of unused locks to be done by the garbage collector. They had been developed here: Iterating a WeakHashMap
If the payment has a reference to its order and equal orders are the same objects (order1 == order2 <=> order1 is the same as order2), you can use a synchronized block:
synchronized(payment.getOrder()) {
try {
// ...
}
}
Caution: You should ensure, that payment.getOrder() does not yield null or use dummy-Objects for that case.
Edit: Possible solution if order1 == order2 does not hold:
You could try holding unique locks for equal identifiers of your order:
static Map<Long, Object> lockCache = new ConcurrentHashMap<>();
and in the method
Object lock = new Object();
Object oldlock = lockCache.putIfAbsent(payment.getOrder().getUid(), lock);
if (oldlock != null) {
lock = oldlock;
}
synchronized(lock) {
// ...
}
Don't forget to remove the key when the work is done.
To use the garbage collection to remove your unused keys you could use a WeakHashMap structure:
private static Map<Long, Reference<Long>> lockCache = new WeakHashMap<>();
public static Object getLock(Longi)
{
Long monitor = null;
synchronized(lockCache) {
Reference<Long> old = lockCache.get(i);
if (old != null)
monitor = old.get();
// if no monitor exists yet
if (monitor == null) {
/* clone i for avoiding strong references
to the map's key besides the Object returend
by this method.
*/
monitor = new Long(i);
lockCache.remove(monitor); //just to be sure
lockCache.put(monitor, new WeakReference<>(monitor));
}
}
return monitor;
}
When you need something more complex like an reentant lock you may use a variation of the following solution:
private static Map<Long, Reference<ReentrantLock>> lockCache = new WeakHashMap<>();
private static Map<ReentrantLock, Long> keyCache = new WeakHashMap<>();
public static ReentrantLock getLock(Long i)
{
ReentrantLock lock = null;
synchronized(lockCache) {
Reference<ReentrantLock> old = lockCache.get(i);
if (old != null)
lock = old.get();
// if no lock exists or got cleared from keyCache already but not from lockCache yet
if (lock == null || !keyCache.containsKey(lock)) {
/* clone i for avoiding strong references
to the map's key besides the Object returend
by this method.
*/
Long cacheKey = new Long(i);
lock = new ReentrantLock();
lockCache.remove(cacheKey); // just to be sure
lockCache.put(cacheKey, new WeakReference<>(lock));
keyCache.put(lock, cacheKey);
}
}
return lock;
}