제목: (멀티 코어를 100% 활용하는) 자바 병렬 프로그래밍 / Java Concurrency in Practice
저자: 브라이어 게츠, 더그 리, 팀 피얼스, 조셉 보우비어, 데이빗 홈즈, 조슈아 블로쉬
출판사: 에이콘
동기화된 클래스의 대표주자: Vector, Hashtable
문제1. 이 역시 동시에 다른 스레드가 item을 추가/삭제할 경우 - ArrayIndexOutOfException이 발생할 수 있음.
- 객체 자체에 synchronized 키워드를 사용하면 되지만 성능이 떨어지게 됨.
문제2. Iterator를 이용한 연산도중 동시성 이슈
- ConcurrentModificationException 발생: 즉시 멈춤(fail-fast)
- 숨겨진 iterator: toString, containAll, removeAll 등의 메소드 내에서 사용됨
병렬 컬렉션
Collections.synchronizedXXX 메소드는 동기화를 우선으로 구현됨. 성능저하.
병렬 컬렉션(java.util.concurrent 패키지에 포함)들은 동기화 보다는 성능을 우선시함. 따라서 연산 도중 size가 바뀔 수 있음.
- ConcurrentHashMap (putIfAbsent와 같이 미리 구현되어 있는 연산 외 추가 연산이 필요할 경우는 ConcurrentMap을 사용하자)
- CopyOnWriteArrayList: 변경할 때마다 복사. Iterator는 뽑아낸 시점 기준으로 동작. 변경보다 읽기 작업이 많은 경우에 사용.
Blocking Queue (Producer-Consumer 패턴)
FileCrawler: 디스크에 들어 있는 디렉토리 계층 구조를 따라가면서 검색 댓아 파일이라고 판단되는 파일 이름을 작업 큐에 쌓는다.
동기화 클래스(Synchronizer)
상태 정보를 사용해 스레드 간의 작업 흐름을 조절할 수 있도록 만들어진 클래스.
ex) Blocking Queue, Latch, FutureTask, Semaphore, Barrier
래치(Latch)
래치가 terminal 상태에 이를 때까지 모든 스레드의 동작을 중단시킨다.
-. 특정자원을 확보하기 전에는 작업을 시작하지 말아야 할 때
-. 의존성을 가지고 있는 다른 서비스가 시작하기 전에는 특정 서비스가 실행되지 않도록 막아야 하는 경우
-. 특정 작업에 필요한 모든 객체가 실행할 준비를 갖출 때까지 기다리는 경우
한 번 terminal 상태에 다다르면 되돌릴 수 없다.
대표적인 래치: CountDownLatch
책의 예제: CountDownLatch를 이용하여 여러 개의 스레드가 동시에 작업을 시작하는 경우 작업을 완료하는 데에 걸리는 시간을 측정
FutureTask
- Executor 프레임웍에서 비동기적인 작업을 할 때,
- 시간이 많이 필요한 작업의 결과를 필요한 시점에 빨리 얻어내기 위해 작업을 미리 시켜 놓을 때 사용
연산작업은 Callable 인터페이스를 구현.
get 메소드는 작업이 종료되었다면 즉시 결과를 리턴, 아니면 종료 상태가 될 때까지 대기.
예외 처리에 주의!
세마포어(Semaphore)
특정 자원을 동시 사용하거나 특정연산을 동시에 호출하는 스레드의 수를 제한하고자 할 때 사용.
ex) 자원 pool이나 컬렉션의 크기에 제한을 두고자 할 때.
생성자에서 permit의 개수를 지정.
acquire 메소드로 permit을 요청하고 허용 가능한 permit이 없을 때는 대기.
release 메소드로 permit을 반납.
이진 세마포어(permit이 1인 경우)는 mutex로 사용 가능.
배리어(Barrier)
실제 작업은 여러 스레드에서 병렬로 처리하고, 다음 단계로 넘어가기 전에 이번 단계에서 계산해야 할 내용을 모두 취합해야 하는 등의 작업이 많이 일어나는 시뮬레이션 알고리즘에서 유용하게 사용 가능.
스레드는 배리어에 도달하면(자신의 작업을 마치면) await를 호출하여 다른 스레드가 배리어에 도달할 때까지 기다린 후 관문을 열고 다음으로 넘어간다.
(래치는 특정 '이벤트'가 일어날 때까지 기다렸다가 작업을 시작한다)
await 호출 후 타이아웃이 걸리거나 대기중 인터럽트가 걸리면 배리어는 깨진 것 으로 간주하고, 대기중인 모든 스레드에 BrokenBarrierException이 발생한다.
CyclicBarrier 클래스를 사용하여 배리어 포인트에서 반복적으로 만나는 기능을 모델링할 수 있다. 커다란 문제를 작은 문제로 분할하여 반복 처리하는 병렬 처리 알고리즘을 구현하고자 할 때 사용.
'요점정리 > 자바 병렬 프로그래밍 Java Concurrency in Practice' 카테고리의 다른 글
06. 작업 실행 (0) | 2014.09.16 |
---|---|
04. 객체 구성 (0) | 2014.09.03 |
03. 객체 공유 (0) | 2014.09.02 |
01. 개요 / 02. 스레드 안정성 (0) | 2014.08.31 |
(멀티 코어를 100% 활용하는) 자바 병렬 프로그래밍 / Java Concurrency in Practice (0) | 2014.08.30 |