遗留代码如下:
private static final ReentrantLock RE_ENTRANT_LOCK = new ReentrantLock(true);
private void newRunTransaction(final OrderPayment payment, final Address billingAddress, final String command) {
TransactionResponse response = null;
RE_ENTRANT_LOCK.lock();
try {
SoapServerPortType client = getClient();
....
我们认为方法开头的锁定是过大的,因为我们应该能够在多个线程中运行事务。另一方面,如果OrderPayment与2个并行线程中的同一订单相关,则我们无法并行运行事务。
是否有任何优雅而有效的方法来确保与一个订单相关的事务不会并行运行,而所有其他事务都是多线程的?
[更新]:添加了使用WeakHashMap-Cache的解决方案,以清理垃圾收集器要使用的未使用的锁。它们是在这里开发的:迭代WeakHashMap
如果付款引用了其订单,并且相等的订单是相同的对象(order1 == order2 <=> order1与order2相同),则可以使用同步块:
synchronized(payment.getOrder()) {
try {
// ...
}
}
警告:您应该确保payment.getOrder()不会产生空值,或者在这种情况下不使用虚拟对象。
编辑:如果order1 == order2不成立,则可能的解决方案:
您可以尝试为订单的相同标识符持有唯一锁:
static Map<Long, Object> lockCache = new ConcurrentHashMap<>();
并在方法中
Object lock = new Object();
Object oldlock = lockCache.putIfAbsent(payment.getOrder().getUid(), lock);
if (oldlock != null) {
lock = oldlock;
}
synchronized(lock) {
// ...
}
完成工作后,请不要忘记删除密钥。
要使用垃圾回收来删除未使用的键,可以使用WeakHashMap结构:
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;
}
当您需要更复杂的东西(例如可重入锁)时,可以使用以下解决方案的一种变体:
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;
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句