并发HashMap迭代器:线程的安全性如何?

时间:2012-08-03 07:27:42

标签: java multithreading thread-safety concurrenthashmap

我使用并发hashmap来创建矩阵。它的指数范围为100k。我创建了40个线程。每个线程访问矩阵的那些元素并对其进行修改并将其写回矩阵:

ConcurrentHashMap<Integer, ArrayList<Double>> matrix = 
    new ConcurrentHashMap<Integer, ArrayList<Double>>(25);

for (Entry(Integer,ArrayList<Double>)) entry: matrix.entrySet())
    upDateEntriesOfValue(entry.getValue());     

我没有发现它是线程安全的。值经常返回为null,我的程序崩溃了。有没有其他方法使其线程安全。或者这是线程安全的,我在其他一些地方有bug。有一件事是我的程序在单线程模式下不会崩溃。

3 个答案:

答案 0 :(得分:11)

iteratorConcurrentHashMap确实是线程安全的。

但是代码中不是线程安全的是你似乎更新的ArrayList<Double>!您的问题可能来自此数据结构。

您可能希望使用适合您需要的concurrent data structure

答案 1 :(得分:2)

使用矩阵的贴图效率非常低,而且使用它的方式,它甚至不会特别支持稀疏数组。

我建议你使用double [] [],你可以锁定每一行(如果更好的话就是列)如果矩阵足够小你可能更好只使用一个CPU,因为这可以节省你很多开销。

我建议你不要创建比核心更多的线程。对于CPU密集型任务,使用更多线程可能更慢,而不是更快。

  

矩阵最大为100k * 50

编辑:根据您正在执行的操作,我会尽量确保您拥有较短的尺寸,以便您可以有效地处理不同线程中的每个长尺寸。

e.g

double[][] matrix = new double[50][100*1000];
for(int i=0;i<matrix.length;i++) {
   final double[] line = matrix[i];
   executorService.submit(new Runnable() {
       public void run() {
          synchronized(line) {
              processOneLine(line);
          }
       }
   });
}

这允许所有线程并发运行,因为它们不共享任何数据结构。他们还可以有效地访问每个双,因为它们在内存中是连续的并且尽可能有效地存储。即100K双打使用大约800KB,但List<Double>使用2800KB,每个值可以随机排列在内存中,这意味着你的缓存必须更加努力。

  

谢谢,但事实上我总共拥有80个核心

要有效地使用80核心,您可能希望将较长的行分成两行或四行,以便您可以保持所有核心繁忙,或者找到一次执行多个操作的方法。

答案 2 :(得分:1)

如果多个线程可以同时在同一个List实例上运行,那么ConcurrentHashMap对于访问Map是安全的线程,但Lists服务的需要是thread-safe所以使用修改时thread-safe list

在你的情况下工作ConcurrentHashMap是安全的,但是当线程转到ArrayList时,这不是synchronized,因此多个线程可以同时访问它,这使得它不是线程安全的。您可以使用synchronized block在列表

中执行修改的位置