반응형
- 컴포넌트의 스레드 안정성을
안정적으로 확보하고 개발자가 코드 작성 과정에서 실수를 해도
스레드 안정성을 해치지 않도록 도와주는 클래스 구성 방법에 대해 알아봄 - 4.1 스레드 안전한 클래스 설계
4.1.1 동기화 요구사항 정리
4.1.2 상태 의존 연산
4.1.3 상태 소유권 - 4.2 인스턴스 한정
4.2.1 자바 모니터 패턴
4.2.2 예제: 차량 위치 추적 - 4.3 스레드 안전성 위임
4.3.1 예제: 위임 기법을 활요한 차량 추적
4.3.2 독립 상태 변수
4.3.3 위임할 때의 문제점
4.3.4 내부 상태 변수를 외부에 공개
4.3.5 예제: 차량 추적 프로그램의 상태를 외부에 공개 - 4.4 스레드 안전하게 구현된 클래스에 기능 추가
4.4.1 호출하는 측의 동기화
4.4.2 클래스 재구성 - 4.5 동기화 정책 문서화하기
4.5.1 애매한 문서 읽어내기 - 클래스가 스레드
안정성을 확보하도록 설계하고자 할 때에는 다음과 같은 세 가지를 고려해야 한다.
1. 객체의 상태를 보관하는 변수가 어떤 것인가?
2. 객체의 상태를 보관하는 변수가 가질 수 있는 값이 어떤 종류, 어떤 범위에 해당하는가?
3. 객체 내부의 값을 동시에 사용하고자 할 때, 그 과정을 관리할 수 있는 정책 - 객체 내부의 여러 변수가 갖고 있는 현재 상태 사용할 때 값이 계속 변하는 상황에서도 안전하게 사용할 수 있도록 조절하는 방법 => 동기화 정책
- 클래스를 유지보수하기 좋게 관리하려면 동기화 정책을 문서로 작성해두어라.
- 객체가 가질 수 있는 값의 범위와 변동 폭을 정확하게 인식해야 함
- 서로 연관된 값은 단일 연산으로 한번에 읽거나 변경해야 함
- 클래스의 상태가
정상적이라는 여러 제약 조건이 있을 경우,
여러 가지 추가적인 동기화 기법을 적용하거나 상태 변수를 클래스 내부에 적절히 숨겨야 함 - 현재 조건에 따라 동작 여부가 결정되는 연산을 상태 의존 연산이라고 함
- 자바에 내장된 wait, notify 명령을 사용하면 특정 상태가 원하는 조건에 다다를 때까지 효율적으로 기다릴 수 있다. 하지만 올바르게 사용하기가 쉽지는 않다.
- wait와 notify를 사용하는 대신 세마포어나 블로킹 큐와 같이 현재 알려져 있는 여러 가지 라이브러리를 사용하는 편이 훨씬 간단하고 안전하다.
- 객체의 상태는
해당 객체 내 모든 객체/변수가 가질 수 있는 전체 상태의 부분 집합
전체 상태 중 인스턴스가 논리적으로 그렇게 변경될 수 없는 상태도 있기 때문에 부분 집합 - 변수를 통해 객체의 상태를 정의하고자 할 때에는 해당 객체가 실제로 소유하는 데이터만을 기준으로 삼아야 한다.
- 공동 소유권 : 변수를 객체 외부로 공개하면 변수에 대한 통제권을 어느 정도 잃으므로 공동 소유권을 가지게 된다.
- 소유권 분리 : 컬렉션 클래스를 놓고 볼때 컬렉션 내부의 구조에 대한 소유권은 컬렉션 클래스가 갖고, 컬렉션에 추가되어 있는 객체에 대한 소유권은 컬렉션을 호출해 사용하는 클라이언트 프로그램이 갖는 구조이다.
- 객체를 적절하게 캡슐화하는 것으로도 스레드 안전성을 확보할 수 있다. 이 경우를 ‘인스턴스 한정’ 이라고 한다.
- 데이터를 객체 내부에 캡슐화해 숨겨두면 숨겨진 내용은 해당 객체의 메소드에서만 사용할 수 있기 때문에 숨겨진 데이터를 사용하고자 할 때에는 항상 지정된 형태의 락이 적용되는지 쉽고 정확하게 파악할 수 있다.
- 인스턴스 한정 기법을 사용하면 전체 프로그램을 다 뒤져보지 않고도 스레드 안전성을 확보하고 있는지 쉽게 파악할 수 있다.
- 자바 모니터 패턴을 따르는 객체는 변경 가능한 데이터를 모두 객체 내부에 숨긴 다음 객체의 암묵적인 락으로 데이터에 대한 동시 접근을 막는다.
- 만약 락이 객체 외부로 공개되어 있다면 다른 객체도 활용해 동기화 작업에 참여 가능함
- 스레드 안전성이 없는 객체를 조합해 만들면서 스레드 안전성 확보하고자 하면 자바 모니터 패턴을 유용하게 사용 할 수 있다.
- 조합하고자 하는
클래스가 안전성을 확보하고 있다면, 상황에 따라 다르다.
단일 객체만 조합한다면 안전함
여러 객체를 단일 락으로 동기화 해야만 안전함 - 안전성을
위임하고자 하는 내부 변수가 두 개 이상이어도 서로 독립적이라면 위임할 수 있음
독립적이라는 말은, 변수가 서로의 상태 값에 대한 연관성이 없다는 말 - 아래처럼 상태 변수간에 의존성을 가지고 있는 경우, 의존성 조건을 정확하게 처리하지 못할 수 있다.
- 숫자 범위가 (0, 10)인 상태에서 스레드A가 setLower(5), 동시에 스레드B가 setUpper(4) 호출 시 (5, 4)로 설정될 수 있다.
- 상태 변수가 스레드 안전하고, 클래스 내부에서 상태 변수의 값에 대한 의존성을 갖고 있지 않고, 상태 변수에 대한 어떤 연산을 수행하더라도 잘못된 상태에 이를 가능성이 없다면 외부에 공개해도 안전함
- 내부 상태를 안전하게 공개하는 차량 추적 프로그램
- 기존 클래스에
직접 추가
- 가장 안전한 방법이지만 외부 라이브러리를 가져다 사용하는 경우 소스코드를 갖고 있지 않을 수도 있고, 소스코드를 갖고 있다 해도 자유롭게 고쳐 쓰지 못하는 경우가 많다.
- 소스코드를 갖고 있다고 하여도 클래스의 동기화 정책을 정확하게 이해하고 사용하여야 한다. - 기존 클래스를
상속받는 방법
- 클래스에 직접 기능을 추가하는 방법보다 문제가 생길 위험이 훨씬 많다.
- 동기화를 맞춰야 할 대상이 두 개 이상의 클래스에 걸쳐 분산되기 때문이다. - 도우미 클래스를 이용하여 동기화하는 나쁜 예
- 도우미 클래스를 이용하여 동기화하는 좋은 예
- 기존 클래스에
새로운 단일 연산을 추가하고자 할 때 재구성(composition)을 사용하면 좀 더 안전하다.
재구성한 클래스 자체가 락이되므로 활용한 클래스가 스레드에 안전한지 상관이 없기 때문! - ImprovedList
의 생성 메소드에 한번 넘겨준 내용은 ImprovedList를 통해서만 접근해야 한다.
(생성 메소드에 넘겨준 list가 외부에 공개된다면 안전하지 않을 수 있다.) - 문서화는 스레드 안전성을 관리하는데 있어 가장 강력한 방법 가운데 하나
- 문서를 충분히 작성해둬야 유지보수 팀이 원활하게 관리할 수 있음
- 최소한 클래스가 스레드 안전성에 대해 어디까지 보장하는지 문서로 남겨야 함
- @GuardBy 활용
- 직관적으로 봤을
때 안전해보이는 클래스도 그렇지 않을 경우가 있음
예) java.text.SimpleDateFormat
4.1 스레드 안전한 클래스 설계
4.1.1 동기화 요구사항 정리
4.1.2 상태 의존 연산
4.1.3 상태 소유권
4.2 인스턴스 한정
4.2.1 자바 모니터 패턴
4.3 스레드 안전성 위임
4.3.2 독립 상태 변수
4.3.3 위임할 때의 문제점
4.3.4 내부 상태 변수를 외부에 공개
4.3.4 내부 상태 변수를 외부에 공개
4.4 스레드 안전하게 구현된 클래스에 기능 추가
4.4.1 호출하는 측의 동기화
4.4.1 호출하는 측의 동기화
4.4.2 클래스 재구성
4.5 동기화 정책 문서화하기
반응형
'개발 > 병렬 프로그래밍' 카테고리의 다른 글
자바 병렬 프로그래밍 - 6장 작업실행 (0) | 2016.08.16 |
---|---|
자바 병렬 프로그래밍 - 5장 구성 단위 (0) | 2016.08.12 |
자바 병렬 프로그래밍 - 3장 객체 공유 (0) | 2016.07.31 |
자바 병렬 프로그래밍 - 2장 스레드 안정성 (0) | 2016.07.14 |
자바 병렬 프로그래밍 - 1장 개요 (0) | 2016.07.14 |