所以我有一个包含很多整数的数组,我正在为它编写单个位来存储信息。像这样:
public class myclass
{
int[] bitArray;
//methods
public myclass()
{
bitArray = new int[200000000]; //200 million ints
}
public void flagBit(int arrayIndex, bitIndex)
{
/** 10000000 00000000 00000000 00000000 >>> bitIndex */
bitArray[arrayIndex] |= (0x80000000 >>> bitIndex);
}
}
现在,正如您所看到的,这是很多数据。因此,效率势在必行。
无论如何,我希望多个线程(安全地)立即将数据写入此数组。不幸的是,在Java中,您无法执行以下操作:
public void flagBit(int arrayIndex, bitIndex)
{
/** 10000000 00000000 00000000 00000000 >>> bitIndex */
synchronized (bitArray[arrayIndex]) //wrong!!! must synchronize to object!
{
bitArray[arrayIndex] |= (0x80000000 >>> bitIndex);
}
}
所以,我想知道最有效或最好的方法是什么?我知道AtomicIntegerArray,但我相信我可以比这更有效率。我试图提出一个解决方案,这就是我得到的(我还没有测试过它,它有效吗?)
public class myclass
{
int[] bitArray;
SYNC[] indexSync;
//inner class(es)
private static final class SYNC
{
private static final boolean sync = false;
}
//methods
public myclass()
{
bitArray = new int[200000000]; //200 million ints
indexSync = new SYNC[bitArray.length];
}
public void flagBit(int arrayIndex, bitIndex)
{
/** 10000000 00000000 00000000 00000000 >>> bitIndex */
synchronized (indexSync[arrayIndex])
{
bitArray[arrayIndex] |= (0x80000000 >>> bitIndex);
}
}
}
那么,有没有比我发布的方式更有效的方法呢?我的发布方式是否有效?我的方式会非常有效吗?感谢〜
答案 0 :(得分:1)
您应该只使用AtomicIntegerArray。它似乎完全符合您的需求,并且是由专家编写的经过良好测试的代码。你应该在扣除它之前测试它的性能。
如果你真的不想使用AtomicIntegerArray,你真的不需要SYNC类,你可以只使用布尔对象。另外,如果你要创建一个完整的第二个SYNC对象数组,那么制作你的第一个数组整数而不是整数可能是值得的。
答案 1 :(得分:1)
引人入胜,他们用Java 8更新了AtomicIntegerArray
类,实际上添加了允许你使用它实现这一功能的功能 - 不,你真的不能比它更有效。
事实上,它比你正在做的更有效率,因为它避免了锁定整体。对于那些坚持使用Java 7或之前的人 - 或者只是想了解其工作原理的人,这里是我在检查新Javadoc之前实际编写的简化版本。
至少教育仍然。这是Java中一个非常基本的比较和交换循环。在许多情况下非常有用,虽然看起来更新AtomicIntegerArray
(也可能是其他类),但对于那些有兴趣从代码中获得最佳性能的人来说,这可能不再那么必要或有用。一旦你将样板代码排除在外,它仍然非常简单。
private static final Unsafe unsafe = getUnsafe();
private static final long arrayBase = getArrayBase();
private static final long arrayScale = getArrayScale();
private static Unsafe getUnsafe() {
try {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
return (Unsafe) theUnsafe.get(null);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
private static long getArrayBase() {
return unsafe.arrayBaseOffset(int[].class);
}
private static long getArrayScale() {
return unsafe.arrayIndexScale(int[].class);
}
private final int[] array = new int[1000];
public void flagBit(int arrayIndex, int bitIndex) {
// offset of array[arrayIndex] from start of array. In practice you'd want to compute the log2
// of arrayScale and just do a shift.
long offset = arrayBase + arrayIndex * arrayScale;
int oldValue, newValue;
do {
// Read array[arrayIndex] volatile, we need the memory ordering guarantee
oldValue = unsafe.getIntVolatile(array, offset);
// Compute new value we want
newValue = oldValue | (0x80000000 >>> bitIndex);
// If the field wasn't updated, update it with newValue and return true, otherwise
// return false and we retry.
} while (!unsafe.compareAndSwapInt(array, offset, oldValue, newValue));
}
答案 2 :(得分:0)
你可以在没有任何同步读/写int数组的情况下设置位是原子的, 除非你做了读 - 修改 - 写操作。