-
AOP, 직접 활용한 경험?! ← 동기화 목적이 아니더라도?!
-
테스트의 목적
- 기능 테스트
- 실제로 의도한 행동을 하는지
- 의도하지 않은 행동을 하고 있지 않은지 → ex) 자원 관리 테스트
- 성능 관련 수치 설정 목적(스레드 개수, 버퍼 크기 등)
-
병렬성을 제어하는 용도로 Thread.getState
를 사용하지 않아야 한다.
- 스레드가 대기 상태에 들어갈 때, JVM의 구현 방법에 따라 spin waiting 기법을 활용할 수 있으므로, 특정 스레드가 대기 상태에 들어갔다고 해서 항상 스레드가
WAITING
or TIMED_WAITING
상태에 놓여 있다고 볼 수 없다.
-
안전성 테스트 시 활용 가능한 방법
- 프로듀서-컨슈머 패턴을 이용해 Queue나 Buffer에 추가된 항목의 개수를 체크 ← 리스트나 큐에 추가/삭제하는 과정에 스레드 동기화 작업이 필요해 테스트 스레드의 스케줄링 부분이 꼬일 가능성 존재
- 큐에 들어가고 나오는 항목의 checksum을 구해 순서를 유지하는 체크섬 형태로 관리하고,, 쌓인 체크섬을 비교해 확인 ← 확장성이 떨어짐, 테스트 사이즈가 커질수록 체크섬 계산이 병목이 될 수 있음
- 스레드 별로 체크섬을 따로 운영하면 동기화할 필요가 없으므로 그게 깔끔함
-
성능 측정 시 주의점
- GC
- 동적 컴파일 → 언제 컴파일이 이뤄지는지 알기 어려움
- 시간 측정 시, IO 기능은 사용하지 않는게 좋음
-
ReentrantLock : synchronized
구문과 동일한 메모리 가시성, 상호 배제 기능 제공
- ReentrantLock / ReentrantReadWriteLock
synchronized
이 제공하지 않는 동기화 기능이 꼭 필요한 경우에만 ReentrantLock을 사용하자.
- 락을 확보할 때 timeout을 지정하는 경우
- 폴링의 형태로 락을 확보하고자 하는 경우
- 락을 확보하느라 대기 상태에 들어 있을 때 인터럽트를 걸 수 있어야 하는 경우
- 대기 상태 큐 처리 방법을 공정하게 하는 경우
- 코드가 단일 블록 형태를 넘어서는 경우
-
ReadWriteLock: 읽기는 여러 스레드가 가능, 쓰기만 한 스레드만 가능
-
락을 확보할 때 시간 제한을 두거나 폴링(trylock) 방법을 사용하면 락을 확보하지 못하는 상황에도 통제권을 얻을 수 있음
-
Lock Striping: 해시 기반 컬렉션 클래스에서 여러 개의 해시 블록을 구성해 블록별로 다른 락을 사용
-
hand-over-hand locking or lock coupling: 링크를 따라가는 알고리즘이나 리스트 연결 구조를 변경할 때 특정 노드에 대한 락을 먼저 확보하고, 그 노드에 연결된 다른 노드에 대한 락을 확보한 다음 원래 노드에 대한 락을 해제
-
공정성: FIFO로 락 확보
-
불공정성: 순서 뛰어넘기(barging) 가능