[java Anti Pattern Series] 21.lockingtoread
February 4, 2025
Locking To Read
- 공유 리소스에 대한 읽기 작업을 보호하기 위해서 잠금을 사용하는 것을 의미한다.
- 멀티쓰레드 환경에서 데이터 일관성르 보장하고 경쟁 조건 방지하기 위해서 사용된다.
- 읽기 작업에 불필요하게 잠금을 하면 병목 포인트가 된다.
문제점
- 읽기 잠금을 획득하면 다른 쓰레드에서 해당 리소스를 읽지 못한다.
- 불필요한 경합으로 직렬화되면 성능이 저하되고 지연 시간이 늘어날 수 있다.
- 올바르게 구현하지 않으면 교착 상태가 발생할 수도 있다.
- 동시성 감소
- 잠재적 교착 상태
- 오버헤드
- 코드 복잡성
대체 접근 방식
읽기·쓰기 잠금
- 읽기/쓰기 잠금은 여러 쓰레드가 동시에 리소스를 읽으면서 동시에 쓰기 전용 액세스를 보장하는 동기화 메커니즘
- 이를 통해서 작업 성능 향상을 할 수 있다.
불변 데이터 사용
- 대안으로 불변 데이터를 사용한다.
- 수정할 수 없으므로 쓰레드에 안전하다.
캐싱
- 자주 액세스하는 데이터를 메모리에 캐싱해서 공유 리소스에 대한 읽기 작업 접근 횟수를 최소화할 수 있다.
- ReadWriteLock
- 불변 데이터 구조
- 휘방성 변수 : 자주 읽지만 거의 수정하지 않는 단순한 변수를 다룰 때
volatile을 사용하면 잠금 없이도 쓰레드 전체에 변경 사항을 확인할 수 있다.
- 더 높은 수준의 동기화 메커니즘 : 원자 변수, 동시 컬렉션, CountDownLatch, CyclicBarrier 등
개선안
- 세분화된 잠금 사용
- 읽기 최적화
- 중첩 잠금 피하기
- 잠금 경합을 모니터링
- 공유 데이터를 읽기 위해서 잠금이 사용되는 코드 섹션 식별
- 데이터 액세스 패턴을 평가하고 읽기가 쓰기보다 많은지 확인
- 여러 쓰레드가 동시에 공유 데이터를 읽을 수 있도록 독점 잠금을 ReadWriteLock으로 대체
- 공유 데이터를 변경 불가하게 만들거나 자바 동시성 유틸리티에서 제공하는 상위 수준의 동기화 메커니즘을 사용하도록 코드 리펙토링
읽기 잠금을 피하려면?
- ConcurrentHashMap
- CopyOnWriteArrayList