Java性能-ArrayList与Arrays相比,可实现大量快速读取

Java性能-ArrayList与Arrays相比,可实现大量快速读取,java,performance,arrays,arraylist,Java,Performance,Arrays,Arraylist,我有一个程序,我需要在尽可能短的时间内(以毫秒为单位)对类似细胞自动机的程序进行100000到1000000次随机访问读取。我认为我使用的更新算法已经过优化(有效地跟踪活动单元等)。列表确实需要改变大小,但性能并没有那么重要。因此,我想知道使用数组而不是ArrayList的性能是否足以在如此短的时间内处理如此多的读取时产生影响。目前,我正在使用ArrayList 编辑: 我忘了提到:我只是存储整数,所以另一个因素是使用整数包装类(在ArrayList中)而不是整数(在arrays中)。有人知道使

我有一个程序,我需要在尽可能短的时间内(以毫秒为单位)对类似细胞自动机的程序进行100000到1000000次随机访问读取。我认为我使用的更新算法已经过优化(有效地跟踪活动单元等)。列表确实需要改变大小,但性能并没有那么重要。因此,我想知道使用数组而不是ArrayList的性能是否足以在如此短的时间内处理如此多的读取时产生影响。目前,我正在使用ArrayList

编辑: 我忘了提到:我只是存储整数,所以另一个因素是使用整数包装类(在ArrayList中)而不是整数(在arrays中)。有人知道使用ArrayList是否需要3个指针查找(一个用于ArrayList,一个用于底层数组,一个用于整数->整数),其中数组只需要1(数组地址+特定整数的偏移量)?HotSpot会优化额外的查找吗?这些额外的查找有多重要

编辑2:
另外,我忘了提到我还需要进行随机访问写入(写入,而不是插入)。

数组会更快,因为它至少会跳过一个函数调用(即get(I))


如果你有一个静态大小,那么数组就是你的朋友。

数组列表比数组慢,但是大多数人认为差异是次要的。但在你的情况下,这可能很重要,因为你要处理成千上万的问题


顺便说一句,复制:

如果您不打算从这个结构中进行更多的读取,那么继续使用数组,因为按索引读取时会更快

但是,考虑一下你将如何获得数据,如果排序、插入、删除等是一个值得关注的问题。如果是这样,您可能需要考虑其他基于集合的结构。

同时尝试这两种方法,但是测量。< /P> 最有可能的是,您可以将一些东西组合在一起,使内部循环使用数组,而无需更改那么多代码。我怀疑HotSpot已经内联了方法调用,您将看不到任何性能提升


另外,请尝试Java6更新14并使用-XX:+DoEscapeAnalysis,我同意Kevin的建议


如果程序运行缓慢,请首先查看列表并测量性能,然后将其与带有数组的版本进行比较。如果这给了您一个可测量的性能提升,那么请使用阵列,如果不使用列表,请继续使用列表,因为它们将使您的生活更加轻松。

一种可能是重新实现ArrayList(这并不难),但通过锁定/释放调用周期公开支持阵列。这为您的写操作带来了便利,但为一系列读/写操作公开了阵列,而您事先知道这些操作不会影响阵列大小。如果列表已锁定,则不允许添加/删除-仅获取/设置

例如:

  SomeObj[] directArray = myArrayList.lockArray();
  try{
    // myArrayList.add(), delete() would throw an illegal state exception
    for (int i = 0; i < 50000; i++){
      directArray[i] += 1;
    }
  } finally {
    myArrayList.unlockArray();
  }
SomeObj[]directArray=myArrayList.lockArray();
试一试{
//myArrayList.add(),delete()将引发非法状态异常
对于(int i=0;i<50000;i++){
directArray[i]+=1;
}
}最后{
myArrayList.unlockArray();
}

此方法继续封装阵列增长/etc。。。ArrayList的行为。

Java对其对象使用双间接寻址,这样它们可以在内存中移动,并且其引用仍然有效,这意味着每个引用查找相当于两个指针查找。这些额外的查找无法完全优化

也许更糟糕的是,缓存性能将非常糟糕。访问缓存中的值要比访问主内存中的值快很多倍。(可能是10倍)如果你有一个int[],你知道这些值在内存中是连续的,因此很容易加载到缓存中。但是,对于Integer[]而言,单个对象的整数可能会随机出现在内存中,并且更可能是缓存未命中。此外,整数使用24个字节,这意味着它们比4个字节的值更不可能放入缓存


如果更新整数,通常会创建一个比更新int值多个数量级的新对象。

。事实上,
ArrayList
中有用的数据位可以存储在寄存器中,尽管您可能会使用更多(
List
size)

您在编辑中提到您正在使用包装器对象。这些确实产生了巨大的差异。如果您通常重复使用相同的值,那么合理的缓存策略可能会很有用(
Integer.valueOf
为-128到128提供相同的结果)。对于基元,基元数组通常会轻松获胜


作为一种改进,您可能希望确保数组中的相邻单元格往往是相邻的(您可以做得比带a的列行更好)。

如果您创建一次列表,并从中执行数千次读取,ArrayList的开销可能很小,可以忽略。如果要创建数千个列表,请使用标准数组。循环中的对象创建很快就会变成二次的,这仅仅是因为实例化成员变量、调用继承链上的构造函数等的所有开销


因此,为了回答您的第二个问题,请坚持使用标准整数而不是整数类。同时,你会很快(或者,慢慢地)知道为什么。

现在你已经提到你的数组实际上是原始类型的数组,考虑使用库中的原始类型类的集合。

@viking在其应用程序中使用Trove报告了显著的(十倍!)加速-请参阅评论。另一方面,Trove集合类型与