[Java] SynchronizedCollections vs ConcurrentCollections[Java] SynchronizedCollections vs ConcurrentCollections

Posted at 2013. 8. 17. 19:04 | Posted in 개발이야기

SynchronizedCollections(동기화된 컬렉션)과 ConcurrentCollections(병렬 컬렉션)



동기화된 컬렉션 클래스는 컬렉션의 내부 변수에 접근하는 통로를 일련화해서 스레드 안전성을 확보했다. 하지만 이렇게 만들다 보니 여러 스레드가 한꺼번에 동기화된 컬렉션을 사용하려고 하면 동시 사용성은 상당 부분 손해를 볼 수 밖에 없다. 하지만 병렬 컬렉션은 여러 스레드에서 동시에 사용할 수 있도록 설계되었다.

ConcurrentMap에는 put-if-absent, replace, condition-remove 등을 정의하고 있다.


기존에 사용하던 동기화 컬렉션 클래스를 병렬 컬렉션으로 교체하는 것만으로도 별다른 위험 요소 없이 전체적인 성능을 상당히 끌어 올릴 수 있다.

<에이콘 - 자바 병렬 프로그래밍(p.137) 발췌>


동기화되지 않은(unsynchronized) 컬렉션

- List: ArrayList, LinkedList

- Map: HashMap

- Set: HashSet

- SortedMap: TreeMap

- SortedSet: TreeSet

- Since JDK 1.2

- 문제점: Thread Safe하지 않다.


동기화된(synchronized) 컬렉션

- Vector, Hashtable, Collections.synchronizedXXX()로 생성된 컬렉션들

- Since JDK 1.2

- 문제점: Thread Safe하나, 두개 이상의 연산을 묶어서 처리해야 할 때 외부에서 동기화 처리를 해줘야 한다. (Iteration, put-if-absent, replace, condition-remove 등)


병렬(concurrent) 컬렉션

- List: CopyOnWriteArrayList

- Map: ConcurrentMap, ConcurrentHashMap

- Set: CopyOnWriteArraySet

- SortedMap: ConcurrentSkipListMap (Since Java 6)

- SortedSet: ConcurrentSkipListSet (Since Java 6)

- Queue 계열:ConcurrentLinkedQueue

- Since Java 5

- 특이사항: Concurrent(병렬/동시성)이란 단어에서 알 수 있듯이 Synchronized 컬렉션과 달리 여러 스레드가 동시에 컬렉션에 접근할 수 있다. ConcurrentHashMap의 경우, lock striping 이라 부르는 세밀한 동기화 기법을 사용하기 때문에 가능하다. 구현 소스를 보면 16개의 락 객체를 배열로 두고 전체 Hash 범위를 1/16로 나누어 락을 담당한다. 최대 16개의 스레드가 경쟁없이 동시에 맵 데이터를 사용할 수 있게 한다. (p.350)

반대로 단점도 있는데, clear()와 같이 전체 데이터를 독점적으로 사용해야할 경우, 단일 락을 사용할 때보다 동기화 시키기도 어렵고 자원도 많이 소모하게 된다. 또한, size(), isEmpty()같은 연산이 최신값을 반환하지 못할 수도 있다. 하지만 내부 상태를 정확하게 알려주지 못한다는 단점이 그다지 문제되는 경우는 거의 없다.


※ Queue, BlockingQueue 인터페이스는 Java 5에서 추가되었다. (Deque, BlockingDeque는 6에서 추가되었다.)

※ Synchronized 컬렉션은 객체 자체에 락을 걸어 독점하게되고, Concurrent 컬렉션은 객체 자체 독점하기가 쉽지 않은 단점이 있지만, 장점이 훨씬 더 많다. Concurrent 컬렉션은 컬렉션 전체를 독점하기 위해서는 충분히 신경을 기울여야 한다.

※ Hash를 기반으로 하는 컬렉션은 hashCode()의 해시값이 넓고 고르게 분포되지 못하면 한쪽으로 쏠린 해시 테이블을 사용하게 되는데, 최악의 경우는 단순한 Linked List와 거의 동일한 상태가 될 수 있다.


//