我已经阅读了一些关于来自多个线程的 Java 数组元素可见性的问题和答案,但我仍然无法真正理解某些情况。为了演示我遇到的问题,我提出了一个简单的场景:假设我有一个简单的集合,通过将元素散列到一个存储桶中,将元素添加到其中一个存储桶中(存储桶就像某种列表) 。并且每个桶都是单独同步的。例如:
private final Object[] locks = new Object[10];
private final Bucket[] buckets = new Bucket[10];
这里有一个水桶i应该由 来守护lock[i]。添加元素代码如下所示:
public void add(Object element) {
int bucketNum = calculateBucket(element); //hashes element into a bucket
synchronized (locks[bucketNum]) {
buckets[bucketNum].add(element);
}
}
由于“桶”是最终的,因此即使没有同步,也不会有任何可见性问题。我的猜测是,通过同步,如果没有最终结果,也不会有任何可见性问题,这是正确的吗?
最后,有点棘手的部分。假设我想从任意线程复制并合并所有存储桶的内容并清空整个数据结构,如下所示:
public List<Bucket> clear() {
List<Bucket> allBuckets = new List<>();
for(int bucketNum = 0; bucketNum < buckets.length; bucketNum++) {
synchronized (locks[bucketNum]) {
allBuckets.add(buckets[bucketNum]);
buckets[bucketNum] = new Bucket();
}
}
return allBuckets;
}
我基本上用新创建的存储桶交换旧存储桶,然后返回旧存储桶。这种情况与前一种情况不同add(),因为我们没有修改数组中引用引用的对象,而是直接更改数组/引用。
请注意,当我持有存储桶 1 的锁时,我不关心存储桶 2 是否被修改,我不需要结构完全同步和一致,只需可见性和接近一致性就足够了。
因此,假设 everybucket[i]只在 下修改过lock[i],你会说这段代码有效吗?我希望能够了解原因和原因,并更好地掌握可见性,谢谢。
慕后森
森林海
相关分类