Svi*_*len 5 java concurrency locking
我希望在一些id的基础上同步方法调用,例如给定对象实例的并发装饰器.
例如:
所有使用param"id1"调用方法的线程应该相互串行执行.
所有其余的,使用不同的参数调用方法,称"id2",应该与使用param"id1"调用方法的线程并行执行,但是再次串行相互执行.
所以在我看来,这可以通过每个这样的方法参数锁定(http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/locks/ReentrantLock.html)实例来实现.每次使用param调用该方法时,将查找对应于特定参数值(例如"id1")的锁定实例,并且当前线程将尝试获取锁定.
在代码中说:
public class ConcurrentPolicyWrapperImpl implements Foo {
private Foo delegate;
/**
* Holds the monitor objects used for synchronization.
*/
private Map<String, Lock> concurrentPolicyMap = Collections.synchronizedMap(new HashMap<String, Lock>());
/**
* Here we decorate the call to the wrapped instance with a synchronization policy.
*/
@Override
public Object callFooDelegateMethod (String id) {
Lock lock = getLock(id);
lock.lock();
try {
return delegate.delegateMethod(id);
} finally {
lock.unlock();
}
}
protected Lock getLock(String id) {
Lock lock = concurrentPolicyMap.get(id);
if (lock == null) {
lock = createLock();
concurrentPolicyMap.put(id, lock);
}
return lock;
}
}
protected Lock createLock() {
return new ReentrantLock();
}
Run Code Online (Sandbox Code Playgroud)
看起来这很有效 - 我用jmeter做了一些性能测试等等.尽管如此,我们都知道Java中的并发性是一件棘手的事情,但我决定在这里征求你的意见.
我不禁想到可能有更好的方法来实现这一目标.例如,通过使用BlockingQueue实现之一.你怎么看?
我也无法确定是否存在获得锁定(即protected Lock getLock(String id)方法)的潜在同步问题 .我正在使用同步集合,但这就够了吗?即不应该像以下那样而不是我现在拥有的东西:
protected Lock getLock(String id) {
synchronized(concurrentPolicyMap) {
Lock lock = concurrentPolicyMap.get(id);
if (lock == null) {
lock = createLock();
concurrentPolicyMap.put(id, lock);
}
return lock;
}
}
Run Code Online (Sandbox Code Playgroud)
那你觉得怎么样?
撇开锁创建问题不谈,该模式是可以的,只是您可能拥有无限数量的锁。通常,人们通过创建/使用条纹锁来避免这种情况。guava 库中有一个很好/简单的实现。
使用番石榴实现的示例代码:
private Striped<Lock> STRIPPED_LOCK = Striped.lock(64);
public static void doActualWork(int id) throws InterruptedException {
try {
STRIPPED_LOCK.get(id).lock();
...
} finally {
STRIPPED_LOCK.get(id).unlock();
}
}
Run Code Online (Sandbox Code Playgroud)