반응형

HashMap, Hashtable, ConcurrentHashMap


이 컬렉션들은 같은 인터페이스를 이용해 만들었기에 역할은 비슷하지만 조금 조금씩 다르게 구현되어있다.

위의 3가지는 Map
 인터페이스를 구현한 컬렉션이다. 따라서 우선적으로 <key, value>구조를 가지게 된다.

 

 

 

Hash Collection 기본 메서드

put(key, value)

해당 컬렉션에 key에 대한 value를 넣어준다.

 

get(key)

key에 해당하는 value를 리턴해준다.

 

clear()
해당 콜렉션의 데이터를 초기화 한다.


containsKey(key)
해당 콜렉션에 입력 받은 key를 가지고 있는지 체크한다.


containsValue(value)
해당 콜렉션에 입력 받은 value를 가지고 있는지 체크한다.


remove(key)
해당 콜렉션에 입력 받은 key의 데이터(key도 포함)를 제거한다.


isEmpty()
해당 콜렉션이 비어 있는지 체크한다. 

 

size()
해당 콜렉션의 엔트리(Entry) 또는 세그먼트(Segment) 사이즈를 반환한다.

 

 

HashMap

 

HashMap은 주요 메소드에 synchronized 키워드가 없다.

그래서 멀티 스레딩에서 동기화 문제에 봉착 할 수 있다.

다른 Hash 컬렉션들과 다르게 key, value에 null을 입력할 수 있다.

 

package HashTest;

import java.util.HashMap;
import java.util.Map.Entry;

public class HashMapTest {
	public static void main(String []args) {
		HashMap<String, Integer> hm = new HashMap<>();
		
		// key, value로 입력이 가능
		hm.put("hello", 123);
		hm.put("world", 345);
		
		// key를 null로 할 수 있고 value도 null로 할 수 있다.
		hm.put(null, 555);
		hm.put("nullKey", null);
		
		System.out.println(hm.get("world") + "\n");

		for(String key : hm.keySet()) {
			System.out.println("key :: " + key + " value :: " + hm.get(key));
		}
		
		// entrySet 메서드는 key, value를 볼 수 있게 해준다.
		for(Entry<String, Integer> s : hm.entrySet()) {
			System.out.println(s.getKey() + " " + s.getValue());
		}
	}
}
345

key :: null value :: 555
key :: nullKey value :: null
key :: world value :: 345
key :: hello value :: 123
null 555
nullKey null
world 345
hello 123

 

 

Hashtable

Hashtable put, get과 같은 주요 메소드에 synchronized 키워드가 선언 되어 있다.

따라서 동기화에는 걱정이 없으나 sychronized 키워드가 선언되면 속도가 많이 저하된다.

HashMap과 달리 key, value에 null을 허용하지 않는다.

 

package HashTest;

import java.util.Hashtable;
import java.util.Map.Entry;

public class HashtableTest {

	public static void main(String[] args) {
		Hashtable<String, Integer> ht = new Hashtable<>();

		ht.put("hello", 123);
		ht.put("world", 321);
		
		// key, value 각각에 null을 허용하지 않는다.
		// ht.put("hello", null);
		// ht.put(null, 123);

		for(String key : ht.keySet()) {
			System.out.println(ht.get(key));
		}
		
		for(Entry<String, Integer> entry : ht.entrySet()) {
			System.out.println("key :: " + entry.getKey() + " value :: " + entry.getValue());
		}
	}

}
123
321
key :: hello value :: 123
key :: world value :: 321

 

ConcurrentHashMap

 

HashMap 동기화 하기 위해 만든 클래스이다.

HashMap과는 다르게 key, value에 null을 허용하지 않는다.

 

package HashTest;

import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapTest {

	public static void main(String[] args) {
		ConcurrentHashMap<String, Integer> chm = new ConcurrentHashMap<>();
		
		chm.put("crocus", 1323);

		chm.putIfAbsent("crocus", 345);
		chm.putIfAbsent("code", 345);
		
		for(Entry<String, Integer> entry : chm.entrySet()) {
			System.out.println(entry.getKey() + " " + entry.getValue());
		}
	}

}
code 345
crocus 1323

 

여기서 putIfAbsent라는 메서드가 있는데

이 메서드는 해당 key가 해시에 존재하면 새로이 넣지 않고 없으면 새로 key,value를 넣어주는 메서드이다.

 

 

 

멀티 스레드 환경에서의 컬렉션 결과

 

Hashtable, Synchronized HashMap, ConcurrentHashMap, synchronizedMap 4가지는 모두 동기화가 잘 되지만

역시 HashMap는 동기화가 되지 않음을 알 수 있다.

package HashTest;

import java.util.Collections;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class HashMain {

	private static final int MAX_THREADS = 10;

	public static int sum = 0;
	private static Hashtable<String, Integer> ht = new Hashtable<>();
	private static HashMap<String, Integer> hm = new HashMap<>();
	private static HashMap<String, Integer> hmSyn = new HashMap<>();
	private static Map<String, Integer> hmSyn2 = Collections.synchronizedMap(new HashMap<String, Integer>());
	private static ConcurrentHashMap<String, Integer> chm = new ConcurrentHashMap<>();

	
	public static void main(String[] args) throws InterruptedException {
		class tFunc implements Runnable{
			@Override
			public void run() {
				for( int i = 0; i < 10000; i++ ){
					String key = String.valueOf(i);
					sum++;
					ht.put(key, i);
					hm.put(key, i);
					chm.put(key, i);
					hmSyn2.put(key, i);
		
					synchronized (hmSyn) {
						hmSyn.put(key, i);
					}
				}
			}
		}
		Thread[] thread = new Thread[10];

		for( int i = 0 ; i < MAX_THREADS; i++ ){
			thread[i] = new Thread(new tFunc());
			thread[i].start();
		}

		for(int i = 0 ; i < MAX_THREADS; i++) {
			thread[i].join();
		}

		System.out.println("Hashtable size is "+ ht.size());
		System.out.println("HashMap size is "+ hm.size());
		System.out.println("ConcurrentHashMap size is "+ chm.size());
		System.out.println("HashMap(synchronized) size is "+ hmSyn.size());
		System.out.println("synchronizedMap size is "+ hmSyn2.size());
		System.out.println(sum);
	}
}
Hashtable size is 10000
HashMap size is 10851
ConcurrentHashMap size is 10000
HashMap(synchronized) size is 10000
synchronizedMap size is 10000
98882
반응형