4

我使用并发哈希图来创建矩阵。它的指数范围为 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 并且我的程序正在崩溃。有没有其他方法可以使其线程安全。或者这是线程安全的,我在其他一些地方有错误。一件事是我的程序不会在单线程模式下崩溃。

4

3 回答 3

11

iterator确实是线程安全的ConcurrentHashMap

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

您可能希望使用适合您需要的并发数据结构。

于 2012-08-03T07:33:57.020 回答
2

对矩阵使用映射确实效率低下,而且按照您使用它的方式,它甚至不会特别好地支持稀疏数组。

我建议您使用 double[][] 锁定每一行(或列,如果这样更好)如果矩阵足够小,您最好只使用一个 CPU,因为这可以为您节省相当多的开销。

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

矩阵最大为 100k*50

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

例如

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);
          }
       }
   });
}

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

谢谢,但实际上我总共有 80 个内核

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

于 2012-08-03T07:41:47.930 回答
1

对 Map的ConcurrentHashMap访问将是线程安全的,但如果多个线程可以同时对同一个 List 实例进行操作,那么提供的Lists服务必须是,因此请使用一段时间进行修改。thread-safethread-safe list

在您的情况下,工作 ConcurrentHashMap是安全的,但是当线程进入时ArrayList不是这样synchronized,因此多个线程可以同时访问它,这使得它不是线程安全的。您可以synchronized block在列表中执行修改的地方使用

于 2012-08-03T07:37:17.513 回答