프로그래밍/자바 성능 튜닝 이야기
[자바 성능 튜닝 이야기] List 어디에 담아야 하는지...
Reference M1
2019. 4. 3. 00:20
List 클래스 중 무엇이 가장 빠를까?
List 관련 클래스들의 성능을 비교해 보기 위해 아래와 같이 JMH 테스트 코드를 만들었다.
데이터를 담을 때 얼마나 시간 차이가 발생하는지 확인해 보자.
@State(Scope.Thread)
@BenchmarkMode({Mode.AverageTime})
@OutputTimeUnit(TimeUnit.MILLISECONDS)
public class ListAdd {
int LOOP_COUNT = 1000;
List arrayList;
List vector;
List linkedList;
@Benchmark
public void addArrayList() {
arrayList = new ArrayList<>();
for (int loop = 0; loop < LOOP_COUNT; loop++) {
arrayList.add(loop);
}
}
@Benchmark
public void addVector() {
vector = new Vector<>();
for (int loop = 0; loop < LOOP_COUNT; loop++) {
vector.add(loop);
}
}
@Benchmark
public void addLinkedList() {
linkedList = new LinkedList<>();
for (int loop = 0; loop < LOOP_COUNT; loop++) {
linkedList.add(loop);
}
}
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(ListAdd.class.getSimpleName())
.forks(1)
.build();
new Runner(opt).run();
}
}
데이터를 넣는 속도는 어떤 클래스든 큰 차이가 없는 것을 볼 수 있다. 이번에는 데이터를 꺼내는 속도를 확인해 보자.
@State(Scope.Thread)
@BenchmarkMode({Mode.AverageTime})
@OutputTimeUnit(TimeUnit.MILLISECONDS)
public class ListGet {
int LOOP_COUNT = 1000;
List arrayList;
List vector;
List linkedList;
int result = 0;
@Setup
public void setUp() {
arrayList = new ArrayList<>();
vector = new Vector<>();
linkedList = new LinkedList<>();
for (int loop = 0; loop < LOOP_COUNT; loop++) {
arrayList.add(loop);
vector.add(loop);
linkedList.add(loop);
}
}
@Benchmark
public void getArrayList() {
for (int loop = 0; loop < LOOP_COUNT; loop++) {
result = arrayList.get(loop);
}
}
@Benchmark
public void getVector() {
for (int loop = 0; loop < LOOP_COUNT; loop++) {
result = vector.get(loop);
}
}
@Benchmark
public void getLinkedList() {
for (int loop = 0; loop < LOOP_COUNT; loop++) {
result = linkedList.get(loop);
}
}
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(ListGet.class.getSimpleName())
.forks(1)
.build();
new Runner(opt).run();
}
}
ArrayList의 속도가 가장 빠르고, Vector와 LinkedList는 속도가 매우 느리다. LinkedList가 터무니없이 느리게 나온 이유는 LinkedList가 Queue 인터페이스를 상속받기 때문이다. 이를 수정하기 위해서는 순차적으로 결과를 받아오는 peek() 메서드를 사용해야 한다.
@Benchmark
public void getPeekLinkedList() {
for (int loop = 0; loop < LOOP_COUNT; loop++) {
result = ((LinkedList)linkedList).peek();
}
}
LinkedList 클래스를 사용할 때는 get 메서드가 아닌 peek()이나 poll() 메서드를 사용해야 한다.
ArrayList와 Vector의 성능 차이가 나는 이유는 ArrayList는 여러 스레드에서 접근할 경우 문제가 발생할 수 있지만, Vector는 여러 스레드에서 접근할 경우를 방지하기 위해서 get() 메서드에 synchronized가 선언되어 있다. 따라서, 성능 저하가 발생할 수밖에 없다.