多线程映射写入基本数组后刷新缓存

时间:2013-08-04 18:23:13

标签: java multithreading visibility

此问题与最新版本的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
   }

2 个答案:

答案 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();
  }
}