此问题与最新版本的Java有关。
我有一个原始的二维数组,大小如下。
int[][] array = new int[numPasses][n*10]; //n threads write; during the i-th pass, the k-th thread writes to array[i] at locations k*10 to (k+1)*10-1.
//the array above is allocated at the beginning, and constantly rewritten.
在传递i
期间,每个n
生成器线程都在array[i]
中写入自己的内存位置,因此在写入过程中没有竞争条件。写完后,m
消费者线程会读取此写入的结果。在完成所有写入之前,我不需要消费者在任何时间点访问array[i]
。
我的第一个问题:以下结构会刷新缓存中的所有生产者写入吗?如果没有,那么如何为原始数组做这个呢? (由于技术原因,我不能使用Atomic * Arrays。)
void flush() {//invoked after writes from all producer threads are done.
if(producerThreadID == 0) {
synchronized(array[i]) {//done at pass i.
}
}
我的第二个问题:有更好的方法吗?
编辑:好的,我接受我想要做的事情基本上不可能使用空的synchronized块。让我们说,代替上面的结构,每个生产者线程都可以访问它自己的传递,即:
int[][] array = new int[numPasses][n*10]; //n = numPasses threads write; during the i-th pass, the i-th thread writes to all elements in array[i].
(这是Zim-Zam的建议。)
我的(希望是最终的)问题:那么,第i个线程中的以下结构是否会确保synchronized
块后消费者线程的可见性?
//i-th producer thread acquires lock on array[i]
void produce() {
synchronized(array[i])
//modify array[i][*] here
}
答案 0 :(得分:0)
您的算法可能会创建false sharing,当两个线程写入附近的内存位置时发生 - 如果thread1和thread2正在写入共享缓存行的数据,则缓存协议将强制thread2阻塞直到或在thread1完成后重新执行,反之亦然。您可以通过使用较粗粒度的并行性来避免这种情况,例如:每个传递使用一个线程(每个数组一个线程)而不是每个数组元素一个线程 - 这样每个线程都在自己的数组上运行,并且可能不会有任何错误共享。
答案 1 :(得分:0)
我会使用Atomics
仔细研究您的原因,因为它们正是您所需要的。
如果确实存在问题,那么您是否考虑过像sun.misc.Unsafe
use一样使用Atomics
?
或者 - 使用包含volatile
字段的对象数组。
class Vint {
public volatile int i;
}
Vint[] arr = new Vint[10];
{
for (int i = 0; i < arr.length; i++) {
arr[i] = new Vint();
}
}