如何同步整数数组的单个元素?

3
如果我想锁定整个数组,可以使用synchronized关键字,如下所示:
int arr[];

synchronized void inc(int a, int b){
    arr[a]=arr[a]+b;
}

但是我能否只锁定数组中的某个元素 arr[a],以便其他线程仍然可以同时读写数组的其他元素?

4个回答

6
也许对您更适合的数据结构是AtomicIntegerArray

这可能是最好的答案,但Ray的答案是我在特定情况下正在寻找的解决方案。 - kooshka

4

虽然不能直接使用,但你可以创建一个与整型数组大小相同的对象数组,并用不同的对象填充数组。因此,当你想锁定整型数组中的特定元素时,你可以在相应索引处锁定该对象:

final Object[] locks = new Object[arr.length]:
for(int i = 0; i < arr.length; i++) {
 locks[i] = new Object();
}

当锁定时:执行以下操作

synchronized(locks[a]) {
  // do something here
}

1

不,数组元素是原始类型,你无法对它们进行锁定。(如果它们是对象也没用,因为锁定只有对可变对象才有帮助。你需要锁定数组索引,而不是该索引处的内容)。

唯一可能想到的构造是创建一个唯一引用数组索引的密钥,并在其上同步(或使用Semaphore),但只有当另一个线程以相同的方式访问数组时才会有所帮助。

我建议您改变设计,摆脱int数组并使用数据结构来同步访问其元素(一个包装在Collections.synchronizedList()内的List将是一个很好的起点)。


0
如果这真的是你的瓶颈,完全不同的结构可能更合适。如果你有8个核心,那么它们必须忙碌,并花费大约1/8的时间添加数字以避免严重的争用。如果执行此操作约占工作量的1/8,您应该设计系统以完全不锁定此操作。
假设您需要在多个线程中获取许多值的总和。例如,在非常长的列表中计算数字出现的次数。
您可以拥有一个同步计数器数组,每次更新都需要相对昂贵的锁定。(同步速度很快,但比添加慢得多)
或者,您可以让所有线程保留自己的总数,然后在最后将它们加起来。最终总数相同,除了您没有使用任何锁定!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接