데이터 추가 속도 테스트는 비슷함으로 데이터 get 테스트만 진행한다.
key값에 1000개의 랜덤데이터를 추가하여 하였으며,
순차적으로 데이터를 get하기, 랜덤으로 데이터를 get하기 2가지의 테스트를 진행하였다.
테스트코드
@State(Scope.Thread)
@BenchmarkMode({Mode.AverageTime})
@OutputTimeUnit(TimeUnit.MICROSECONDS) //밀리세컨드 단위로 출력
@Fork(value = 2, jvmArgs= {"-Xms4G", "-Xmx4G"})
public class MapGet {
static int LOOP_COUNT=1000;
Map<Integer,String> hashMap;
Map<Integer,String> hashtable;
Map<Integer,String> treeMap;
Map<Integer,String> linkedHashMap;
int keys[];
@Setup
public void setUp(){
if(keys==null || keys.length!=LOOP_COUNT){
hashMap = new HashMap<>();
hashtable = new Hashtable<>();
treeMap = new TreeMap<>();
linkedHashMap = new LinkedHashMap<>();
String data = "abcdefghijklmnopqrstuvwxyz";
for (int i=0; i<LOOP_COUNT; i++){
String tempData = data+i;
hashMap.put(i,tempData);
hashtable.put(i,tempData);
treeMap.put(i,tempData);
linkedHashMap.put(i,tempData);
}
keys = RandomKeyUtil.generateRandomSetKeysSwap(LOOP_COUNT);
}
}
@Benchmark
public void getSeqHashMap(){
for (int i=0; i<LOOP_COUNT; i++){
hashMap.get(i);
}
}
@Benchmark
public void getRandomHashMap(){
for (int i=0; i<LOOP_COUNT; i++){
hashMap.get(keys[i]);
}
}
@Benchmark
public void getSeqHashTable(){
for (int i=0; i<LOOP_COUNT; i++){
hashtable.get(i);
}
}
@Benchmark
public void getRandomHashTable(){
for (int i=0; i<LOOP_COUNT; i++){
hashtable.get(keys[i]);
}
}
@Benchmark
public void getSeqTreeHash(){
for (int i=0; i<LOOP_COUNT; i++){
treeMap.get(i);
}
}
@Benchmark
public void getRandomTreeHash(){
for (int i=0; i<LOOP_COUNT; i++){
treeMap.get(keys[i]);
}
}
@Benchmark
public void getSeqLinkedHashMap(){
for (int i=0; i<LOOP_COUNT; i++){
linkedHashMap.get(i);
}
}
@Benchmark
public void getRandomLinkedHashMap(){
for (int i=0; i<LOOP_COUNT; i++){
linkedHashMap.get(keys[i]);
}
}
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(MapGet.class.getSimpleName())
.forks(2)
.warmupIterations(10)
.measurementIterations(10)
.build();
new Runner(opt).run();
}
}
public class RandomKeyUtil {
public static int[] generateRandomSetKeysSwap(int n){
int size = n;
int[] result = new int[size];
Random random = new Random();
int maxNumber = size;
int resultPost=0;
while (size>0){
result[resultPost++]=size--;
}
for(int loop=0; loop<size; loop++){
int randomNum1 = random.nextInt(maxNumber);
int randomNum2 = random.nextInt(maxNumber);
int temp=result[randomNum2];
result[randomNum2]=result[randomNum1];
result[randomNum1]=temp;
}
return result;
}
}
다른건 대부분 비슷한 성능으로 나왔으며
TreeMap
이 가장 느리게 나왔다.각 클래스의 용도가 모두 다르기 때문에 용도에 맞게 쓰여야 한다.
비슷한점
ArrayList 와 Vector의 관계랑 비슷함으로
HashTable
보단HashMap
사용이 권장된다.
데이터가 많은경우
초기에크기를 크게 지정
하는것이 권장됨해싱을 사용하기 때문에
검색처리에서 뛰어난 성능
을 보인다.다른점
HashTable
은Thread-Safe
하여동기화를 지원
일반적으로 Map 자료구조는 순서가 없지만
LinkedHashMap
는데이터가 들어온 순서
를 알 수 있다.LFU(Least Frequencd Used) 캐시에서도 쓰여 removeEldestEntry() 메서드를 오버라이드 하면 오랫동안 사용되지 않은 데이터를 삭제해주는 기능을 제공한다.
@Override protected boolean removeEldestEntry(Map.Entry<String, Integer> eldest) { //최대 수용량을 넘는경우 가장 오래된 요소를 삭제 return size()>capacity; }
데이터를 추가하거나 삭제할때 동시에 내부적으로 정렬을 한다.(레드 블랙 트리)
때문에 저장 삭제 변경과 같은 작업은 느리다.
범위 검색 같은 경우에 뛰어난 성능을 보인다.
TreeSet
도레드 블랙 트리
로 구현되어있다.
TreeSet과의 차이점
은TreeSet은 키값만 저장
하지만TreeMap은 키, 값이 저장된 Map.Entry를 저장
한다,