이전 글인 "Collection과 Thread 2"에서 공부할 것으로 분류했던 클레스들의 정체를 밝히는 것으로 본 시리즈의 막을 내리려고 합니다.

총정리 및 발표는 이번주 AJN 정모에서 하게 됩니다. 혹시라도 차후 Agile Java 3기에 참여하실 분들 중에서 관심있으신
분들께서는 이메일 주소 남겨주시면 특별히 무료로 이번 정모에 참석하실 수 있도록 안내 메일 보내 드리겠습니다.

그럼 다시 본론으로 돌아가서 Java 5.0에서 Concurrent Collection이라는 것들을 추가했습니다. 그것들이 바로 이전 글에서 잘 모르겠다고 했던 클래스들입니다.

Concurrent Collections

CopyOnWriteArrayList

ConcurrentSkipListSet,
CopyOnWriteArraySet

ConcurrentLinkedQueue

ConcurrentHashMap,
ConcurrentSkipListMap

이녀석들이죠. 기존에 존재하던 Syncronized Collection을 사용하면 모든 메소드들이 전부 키를 사용하여 롹킹되기
때문에 완전한 Thread-Safety는 보장이 되지만 그에 따른 비용이 발생하게 됩니다. 데드락이 발생할 수 있는 여지가
생기며, 여러 쓰레드가 대기 상태에 머무를 수 있습니다.

하지만 Concurrent Collection은 멀티 쓰레드 환경에서 하나의 데이터에 여러 쓰레드가 동시에 읽는 것을
허용하면서도 쓰기 작업은 하나의 쓰레드만 하도록 롹킹을 Fine-grained하게 적용했습니다. 따라서 기존의
Syncronized Collection에 비해 퍼포먼스가 좋을 것이며 주된 차이점으로는 iteration할 때
fail-fast가 발생하지 않는 다는 것입니다.

ConcurrentHashMap 은 동기화 된 Map 구현체를 대체 하기 위해 만들어졌습니다.
ConcurrentSkipListMap 은 동기화 된 SortedMap 을 대체 하기 위해 Java 6.0 에 추가 됐습니다.
CopyOnWriteArrayList 는 동기화 된 List 구현체를 대체 하기 위해 만들어졌습니다.
ConcurrentSkipListSet 는 동기화 된 SortedSet 을 대체 하기 위해 Java 6.0 에 추가 됐습니다.
CopyOnWriteArraySet 는 동기화 된 Set 구현체를 대체 하기 위해 만들어졌습니다.
ConcurrentLinkedQueue 는 동기화 된 Queue 구현체를 대체 하기 위해 만들어졌습니다.


ConcurrentHashMap 살펴보기

위에서 언급했다시피 모든 메소드에 롹킹을 하는 Syncronized Collection과는 다르게 읽기 작업을 하는 메소드는
롹킹을 걸지 않고 쓰기 작업을 하는 메소드에 롹킹을 걸어서 특정 수의 쓰기 작업한 동시적으로 처리할 수 있도록 합니다.

또한 ConcurrentModificationException을 발생시키지 않습니다. 콜렉션이 수시로 변할 수 있다는 가정하에
Fail-fast 검증 방식을 사용하지 않는 것입니다. 어차피 멀티 쓰레드 상황이면 당연히 수시로 변할 수 있다는 가정을 가지고
간다면 타당한 예외 처리 방법이기도 합니다.

장점만 있는 것은 아닙니다. 콜렉션이 수시로 변할 수 있다는 가정하에 동기화(weakly consistent)를 제공하고 있기 때문에 size 나 isEmpty 메소드의 정확함을 보장하지 못합니다.

또 다른 단점으로는 exclusive access(상호배제) 를 제공하지 못합니다. 상호배제는 운영체제 시간에 들었던 것으로
멀티프로세스에 관한 이야기에서 나온 것인데 고스란히 쓰레드에도 적용할 수 있겠습니다. 즉 여러 쓰레드가 하나의 공유자원에
접근하고자 할 때 하나의 쓰레드가 공유자원에 접근하여 작업하는 중에는 다른 모든 쓰레드는 중단된 상태여야 하는데 이것을
상호배제라고 합니다.(그걸 구현한 방법중 하나가 key를 사용한 locking이고 모니터랑 세마포어 같은 것들도 있습니다.)

상호배제를 사용하지 못하는 단점을 보완할 수 있는 인터페이스를 제공합니다. 바로 ConcurrentMap 인터페이로서
put-if-absent, remove-if equal, replace-if-equal 같은 메소드를 제공합니다.

사용자 삽입 이미지
이 클레스와 같은 원리로 다른 ConcurrencyXXX 클레스들도 똑같이 동작합니다.

CopyOnWriteArrayList 살펴보기

동기화 된 List 구현체들 대신으로 사용할 수 있으며 iteration 할 때 콜렉션을 복사 하거나 메소드들에 롹을 걸 필요를 없애주면서 동시성을 제공하는 클레스입니다.

콜렉션에 쓰기 작업을 Thread-safety를 보장하기 위해 매번 수정된 콜렉션의 복사체를 제공하여 해결합니다. 따라서 ConcurrencyModificationException을 발생시키지 않으며(snapshop을 사용하기 때문이죠.), iteration을 하는 모든 쓰레드는 동기화 할 필요가 없으며 복사체를 가질 순간의 콜렉션의 상태를 기반으로 정확하게 동작하게 됩니다.

하지만 콜렉션이 수정 될 때 마다 복사하는 비용이 발생하며 특히 덩치가 큰 콜렉션의 경유 콜렉션에 수정하는 작업보다 iteration하는 작업이 많을 때 이 클레스의 사용이 적당하겠습니다.

이 클레스와 같은 원리로 CopyOnWriteArraySet 클레스도 똑같이 동작합니다.