As of 2020 there's no need to use LinkedList:
- empty ArrayList is more lightweight than LinkedList:
@State(Scope.Thread)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Fork(jvmArgsAppend = {"-Xms2g", "-Xmx2g"})
public class ListBenchmark {
@Benchmark
public Object arrayList() {
return new ArrayList<>();
}
@Benchmark
public Object linkedList() {
return new LinkedList<>();
}
}
which on JDK 11 gives
ListBenchmark.arrayList avgt 15 4.011 ± 0.120 ns/op
ListBenchmark.arrayList:·gc.alloc.rate.norm avgt 15 24.002 ± 0.001 B/op
ListBenchmark.linkedList avgt 15 4.243 ± 0.181 ns/op
ListBenchmark.linkedList:·gc.alloc.rate.norm avgt 15 32.002 ± 0.001 B/op
if we put one element then LinkedList wins:
enchmark Mode Cnt Score Error Units
ListBenchmark.arrayList avgt 15 9.188 ± 0.831 ns/op
ListBenchmark.arrayList:·gc.alloc.rate.norm avgt 15 80.005 ± 0.001 B/op
ListBenchmark.linkedList avgt 15 8.148 ± 0.285 ns/op
ListBenchmark.linkedList:·gc.alloc.rate.norm avgt 15 56.004 ± 0.001 B/op
in other cases LinkedList looses:
2 elements
Benchmark Mode Cnt Score Error Units
ListBenchmark.arrayList avgt 15 11.308 ± 0.290 ns/op
ListBenchmark.arrayList:·gc.alloc.rate.norm avgt 15 80.006 ± 0.001 B/op
ListBenchmark.linkedList avgt 15 11.898 ± 0.608 ns/op
ListBenchmark.linkedList:·gc.alloc.rate.norm avgt 15 80.006 ± 0.001 B/op
3 elements
ListBenchmark.arrayList avgt 15 14.763 ± 1.452 ns/op
ListBenchmark.arrayList:·gc.alloc.rate.norm avgt 15 80.006 ± 0.001 B/op
ListBenchmark.linkedList avgt 15 19.166 ± 1.686 ns/op
ListBenchmark.linkedList:·gc.alloc.rate.norm avgt 15 104.008 ± 0.001 B/op
ArrayListprovides better data locality and less cache-misses due to usage of arrayLinkedListconsumes much more memory per element, see https://stackoverflow.com/a/7671021/12473843- the only case when
LinkedListcould probably win (re-use of existing iterators to insert and remove elements) are comparatively seldom, in most of the cases we just store elements and iterate over them - if frequently used
LinkedListgets C2-compiled and thus requires space in Code Cache
Comment From: jhoeller
Since we've done such a pass towards ArrayList before (#21575 and further ones), there should be a limited amount of LinkedList usage in the codebase already, mostly for cases where there is usually only one element to keep (similar to the performance indications above). I'll do one more pass for 5.3, pretty sure there are further cases than we can easily switch to ArrayList (although probably not very performance relevant, mostly just configuration storage).
Comment From: jhoeller
Would using new ArrayList(0) / new ArrayList(1) get us close to the LinkedList numbers for the empty and one-element case, respectively? We're mostly just trying to avoid the 10-element array allocation for scenarios with one element... and also to initialize empty lists such that they don't grow to a 10-element array just for one element added eventually.
Comment From: wind57
@jhoeller yes, it should get a lot closer to those. there has been some discussion here https://stackoverflow.com/questions/56647032/why-does-using-different-arraylist-constructors-cause-a-different-growth-rate-of for example (disclaimer: I asked that question).