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

Java 并发HashMap迭代器:线程的安全性如何?,java,multithreading,thread-safety,concurrenthashmap,Java,Multithreading,Thread Safety,Concurrenthashmap,我使用并发hashmap创建了一个矩阵。它的指数范围为100k。我已经创建了40个线程。每个线程访问这些矩阵元素,并对其进行修改,然后将其写回矩阵,如下所示: ConcurrentHashMap<Integer, ArrayList<Double>> matrix = new ConcurrentHashMap<Integer, ArrayList<Double>>(25); for (Entry(Integer,ArrayList&l

我使用并发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());     
ConcurrentHashMap矩阵=
新ConcurrentHashMap(25);
对于(Entry(Integer,ArrayList))条目:matrix.entrySet())
upDateEntriesOfValue(entry.getValue());

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

迭代器对于
ConcurrentHashMap
来说确实是线程安全的

但是代码中不安全的是您似乎要更新的
ArrayList
!您的问题可能来自此数据结构


您可能需要使用适合您需要的。

对于访问映射,
ConcurrentHashMap
将是线程安全的,但是
列表
需要是线程安全的,如果多个线程可以同时在同一个列表实例上操作,那么在修改时使用线程安全列表


在您的例子中,处理
ConcurrentHashMap
是线程安全的,但是当线程转到
ArrayList
时,这不是
synchronized
,因此多个线程可以同时访问它,这使它成为非线程安全的。您可以使用
synchronized block
,在列表中执行修改

使用矩阵的映射效率非常低,而且您使用它的方式,它甚至不能很好地支持稀疏数组

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

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

矩阵最大为100k*50

编辑:根据您正在执行的操作,我将尝试确保您首先拥有较短的维度,以便您可以在不同的线程中高效地处理每个长维度

e、 g

double[][]矩阵=新的double[50][100*1000];

对于(int i=0;i有足够的内核。这对我来说不是什么大问题。矩阵最大为100k*50。没有多少人有40个内核。我建议您使用
Runtime.availableProcessor()
以确保您使用的是所有CPU。哪种型号的机器支持80核。通常是16个四核或16个十六核。您有16*5核吗?您建议我使用同步arraylist吗?同步arraylist可以工作,因为一次只能由一个线程访问。但根据您添加和读取元素的方式,y如果您事先知道大小并希望访问特定索引,您可能想尝试使用
LinkedBlockingQueue
甚至java.util.concurrent.atomic数组。这主要取决于您的需要。您是否尝试从同步数组列表开始?它解决了您的问题吗?我使用了包中的atomic Doulbe数组而不是arraylisgauva。我仍然有同样的问题。然后你的问题来自其他地方。试着分离包含问题的代码段,如果你被卡住了,发布一个新问题。
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);
          }
       }
   });
}