我有一个多线程应用程序,我想在String
上使用重入锁定。例如,如果我使用普通同步,我的代码看起来就像。
我不希望两个相同IP地址的线程进入我的loadBalance()
,所以我锁定IP地址,这是正常工作。
class A {
String ipAddress;
...
void loadBalance() {
synchronized (ipAddress) {
// Business logic goes here
}
}
}
现在如果我在这里使用可重入的API,那么代码将如下所示。现在我的代码中输入了两个相同IP地址的线程,这是不需要的。所以我需要知道如何使用重入API来防止这种情况。
class A {
String ipAddress;
ReentrantLock lock = new ReentrantLock();
...
void loadBalance() {
lock.lock();
// Business logic goes here
lock.unlock();
}
}
我的查询是如何使用Re-entrant
锁定IP地址,就像我在synchronized block
中所做的那样。
答案 0 :(得分:2)
不是每个String
都有一个锁,这可能会导致锁的数量不断增加,最终可能是OutOfMemoryError
,在这种情况下最好使用条带锁定策略。
制作有限数量的锁(假设n
),将它们存储在一个数组中。如果您需要锁定给定的String
,请使用其hashCode()
和模n
来确定哪个数组元素包含要使用的锁。等于String
s将使用相同的锁。
private static final int N = 10;
private ReentrantLock[] locks = new ReentrantLocks[N];
{
for (int i = 0; i < N; i++) {
locks[i] = new ReentrantLock();
}
}
...
// where you need a lock :
String ipAddress = ...
ReentrantLock lock = locks[ipAddress.hashCode() % N];
lock.lock();
权衡是一些不相等的String
s也将使用相同的锁。您应该使用不同数量的n进行测试,以在不需要的锁争用和内存之间取得平衡。
或者你可以使用Guava的Striped
类
答案 1 :(得分:0)
我找到了一种方法,但不确定这个方法是否正确。
我找到了一个class
,它会对提供的String
名称提供锁定
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
public class LockByName<L> {
ConcurrentHashMap<String, L> mapStringLock;
public LockByName() {
mapStringLock = new ConcurrentHashMap<String, L>();
}
public LockByName(ConcurrentHashMap<String, L> mapStringLock) {
this.mapStringLock = mapStringLock;
}
@SuppressWarnings("unchecked")
public L getLock(String key) {
L initValue = (L) createIntanceLock();
L lock = mapStringLock.putIfAbsent(key, initValue);
if (lock == null) {
lock = initValue;
}
return lock;
}
protected Object createIntanceLock() {
return new ReentrantLock();
}
}
class A {
String ipAddressl
LockByName<ReentrantLock> reentrantLocker = new LockByName<ReentrantLock>();
...
ReentrantLock reentrantLock1 = reentrantLocker.getLock(ipAddress);
try {
reentrantLock1.lock();
// DO WORK
} finally {
reentrantLock1.unlock();
}
}