java中是否有一个结构或库可以用作“锁的哈希表”?
我正在存储可由多个线程访问的大量哈希值。我想在这个数组上同步替换操作。锁定索引本身不起作用,因为我正在使用一个基元数组。由于我需要的元素数量,我不想存储同样长的Objects()。相反,我希望缩小我的哈希值并根据它进行锁定。
我正在对前一个值进行更新替换条件,而不是添加,因此排除了jdk中的一些并发库。
以下是我对实施的尝试:
private final Object[] locks = new Object[256];
{
for (int i = 0; i < 256; i++) {
locks[i] = new Object();
}
}
final static int p = 64;
byte[] hashTable = new byte[1 << p];
int populatedCount = 0;
public void add(String s, int i) {
int h = GetHash(s);
int hashBucket = h >>> (32 - p);
int lockHash = h & 0xFF;
int oldValue;
synchronized (locks[lockHash]) {
oldValue = this.hashTable[hashBucket];
this.hashTable[hashBucket] = (byte) Math.max(this.hashTable[hashBucket], i);
}
if (oldValue == 0) {
this.populatedCount++;
}
}
我真正需要的是一个稀疏的并发原始数组......
答案 0 :(得分:2)
如果理解错误,则需要以原子方式获取和替换基本数组的操作(此处:int [])。正确的吗?
如果是这样,您应该阅读AtomicInteger。这是一个完全提供这些原子操作的类。你可以制作一个AtomicInteger []。
但是 - 在探索Java API时,可以找到更好的解决方案:AtomicIntegerArray。该类的一个对象在其和字段中包含一个int [],它对其值提供原子操作。
修改
嗯......在持有锁时首先进行计算(在这种情况下是最大值)的要求似乎有点棘手。
以下子类可能会起到作用:
public class MyAtomicIntegerArray extends AtomicIntegerArray {
// constructors (see also class AtomicIntegerArray)
public int setIfGreater(int index, int value) {
while(true) {
int oldValue = get(index);
int newValue = Math.max(value, oldValue);
if(compareAndSet(index, oldValue, newValue))
return oldValue;
}
}
}
需要while(true)
,因为如果另一个线程在此期间更新了该值,compareAndSet
方法可能会返回false
。在这种情况下,我们需要再次计算。
之后,您在代码中使用此类和此方法:
private static final ARRAY_SIZE = ...;
private final MyAtomicIntegerArray hashTable = new MyAtomicIntegerArray(ARRAY_SIZE);
public void add(String s, int i) {
int h = GetHash(s);
int hashBucket = h >>> (32 - p);
int oldValue = hashTable.setIfGreater(hashBucket, i);
if (oldValue == 0) {
this.populatedCount++;
}
}
答案 1 :(得分:0)
我想这个解决方案更像是一个黑客,只有当你的整数键在0-255 / -128到127范围内时才有效。
您已经讨论了如何仅仅因为原语而无法对原始键进行同步。为什么不将它转换为对象呢?
获取lastHash
值并对其应用Integer.valueOf()
方法以获取Integer对象,然后同步Integer对象本身:
public void add(String s, int i) {
int h = GetHash(s);
int hashBucket = h >>> (32 - p);
int lockHash = h & 0xFF;
int oldValue;
//Subtract 128 to move the range of values into the cached range of -128 to 127.
Integer lockVal = Integer.valueOf(lockHash - 128);
synchronized (lockVal) {
oldValue = this.hashTable[hashBucket];
this.hashTable[hashBucket] = (byte) Math.max(this.hashTable[hashBucket], i);
}
if (oldValue == 0) {
this.populatedCount++;
}
}
对于从-128到127的数字返回的Integer对象将始终相同,因为此处显示的Integer.valueOf()方法中定义了缓存:
此方法将始终缓存-128到127(包括端点)范围内的值,并可以缓存此范围之外的其他值。
在这种情况下,你在技术上得到了一系列缓存的对象,并保证在整数范围-128到127之间不会改变,因此在这些数字上调用Integer.valueOf()对你的情况来说是完美的。 / p>