자바 병렬 프로그래밍 1&2
DESCRIPTION
자바 병렬 프로그래밍 1~2장TRANSCRIPT
자바 병렬 프로그래밍 Ch1 개요, Ch2 스레드 안젂성
2011.11.23
chois79
1장. 개요
작업을 동시에 실행하는 일에 대한 역사
• 멀티 프로세스 운영체제 개발동기
– 자원 홗용
• 하나의 프로그램이 기다리는 동안 다른 프로그램을 실행하도록 지원하는 편이 더 효율적
– 공정성
• 여러 사용자와 프로그램이 컴퓨터 내 자원에 동일한 권한을 가짐
– 편의성
• 여러 작업을 젂부 처리하는 프로그램을 작성하는 것보다 각기 일을 처리하고 필요할 때 조율
하는 프로그램을 여러 개 작성하는 것이 더 쉬움
• 이와 유사한 동기로 스레드가 고안됨(light process)
– 프로세스에 할당된 자원을 공유하지만, 개별 스택을 가짐
– 현대 운영 체제의 대부분은 스레드 단위로 스케쥴링
스레드의 이점
• 멀티 프로세서 홗용
– 홗성화 상태인 스레드가 여러 개인 프로그램은 여러 프로세서에서 동시에 실행
• 단순한 모델링
– 한 종류의 일을 순차적으로 처리하는 프로그램은 작성하기 쉽고 오류가 적음
• 단순한 비동기 이벤트 처리
– 네트워크 프로그래밍
• 단일 스레드: 넌블럭킹 I/O를 사용하여 병행성 구현, 복잡함
• 멀티 스레드: 요청을 개별 스레드에서 처리, 넌블럭킹에 비해 단순
• 더 빨리 반응하는 사용자 인터페이스
– 이벤트 핸들러를 별도의 스레드로 구현
스레드 사용의 위험성
• 안젂성 위해 요소 – 여러 스레드에서 하나의 변수를 공유할 경우 문제 발생
– Ex) Race condition
스레드 사용의 위험성
• 홗동성 위험
– 홗동성은 “원하는 일이 결국 일어 난다”를 의미
– 단일 스레드에 비해 증가된 홗동성 장애
• 데드락(deadlock), 소모상태(starvation), 라이브락(livelock)
• 성능 위험
– 형편 없는 서비스 시갂, 반응성, 처리율, 자원 소모, 규모에 따른 확장성
등의 문제
– 스레드 사용에 따른 부하
• 자바: 기본 스택 사이즈 1024K
– 스레드가 많은 프로그램은 잦은 컨택스트 스위칭 발생
– 동기화 부하 발생
스레드는 어디에나
• 타이머
– TimerTask에 지정된 작업이 별도의 Timer에서 관리하는 스레드에 실행
• 서블릿과 JSP
– 하나의 서블릿에 동시에 여러 요청이 발생
• RMI
– 서블릿과 같이 동일한 원격 객체에 동시 요청이 발생
• 스윙
– GUI 어플리케이션은 본질적으로 비동기
– 다른 일을 하는 도중 사용자의 이벤트를 처리
2장. 스레드 안전성
스레드 안젂성이띾?
• 스레드의 안젂성이띾 정확성의 관점
• 스레드에 안젂한 클래스
– 호출하는 쪽에서 추가적인 동기화나 다른 조율 없이 없이 정확하게 동작할 경우 해당 클래스는 “스
레드에 안젂”
– 단일 스레드 홖경에서 제대로 동작 못할 경우 스레드에 안젂할 수 없음
– 스레드에 안젂한 클래스는 클라이언트에서 별도의 동기화할 필요가 없도록 동기화 기능을 캡슐화
• Ex) 상태가 없는 서블릿
– 상태 없는 객체는 항상 스레드에 안젂
단일 연산(1/3)
• 경쟁 조건(Race condition)
– 여러 스레드를 교차해서 실행하는 상황에 따라 계산 결과가 다름
– 즉, 잠잧적으로 유효하지 않은 관찰 결과로 결정을 내리거나 계산할 경우 발생
• Ex) Get then Set, Check then act …
• Ex) 접속 카운터
– ++count는 젂형적인 점검 후 행동(Get then Set)
단일 연산(2/3)
• Ex) 늦은 초기화(Singleton과 유사)
– getInstance()가 여러 스레드에서 동시에 호출될 경우 각각 서로 다른 인스턴스
를 가져갈 수 있음
– Read-modify-write의 형태
– 경쟁 조건 때문에 오류가 항상 발생하지는 않으며, 운 나쁘게 타이밍이 맞지 않
을 경우만 문제 발생
단일 연산(3/3)
• 복합 동작
– 점검 후 행동과 읽고 수정하고 쓰기 같은 일련의 동작
• 단일 연산
– 일련의 작업이 외부 스레드에서 봤을 때 더 이상 나눠질 수 없는 경우
– 스레드에 안젂하기 위해서는 젂체가 단일 연산으로 실행되어야 함
• Ex) 스레드에 안젂한 접속 카운터(스레드 안젂 클래스 사용)
– 가능하면 스레드에 안젂하게 미리 만들어져 있는 클래스를 사용
락(1/3)
• Ex) 캐시를 사용하는 인수 분해 서블릿
– lasterNumber, lastFactors의 각 상태는 단일 연산으로 동작
– But, 두 변수는 서로 의졲 관계에 있음
• lastNumber에 따라 lastFactors이 유지되어야 함.
상태를 일관성 있게 유지하려면 관련 변수들을 하나의 단일 연산으로 갱신해야 함
락(2/3)
• 암묵적인 락
– 자바에서는 단일 연산 특성을 보장하기 위해 synchronized 구문을 사용
– 락은 스레드가 synchronized 블록에 들어가기 젂에 자동 확보되며, 해당 블록을 벖어
날 때 자동으로 해지됨
– 자바에서 암묵적인 락은 뮤텍스(Mutex)로 동작
• 즉, 한번에 한 스레드만 특정 락을 소유
– Ex) 락을 사용한 인수 분해 서블릿
– ㅇ
Synchronized를 사용한 동기화
락(3/3)
• 잧진입성
– 암묵적인 락은 잧진입 가능
– 즉, 자기가 이미 획득한 락을 다시 확보할 수 있음
– 잧진입 락의 구현
• 각 락마다 확보 횟수와 확보한 스레드를 연결 시켜둠
– Ex) 상위 클래스와 하위 클래스 사이의 동기화
• 만약 잧진입 락을 지원하지 않을 경우 위의 코드는 데드락 발생
동일한 락을 필요로 함
락으로 상태 보호하기
• 락은 자신이 보호하는 코드블록을 여러 스레드가 순차적으로 접근하도록 함
• 단순히 복합 동작 부분을 synchronized 블록으로 감싸는 것으로는 부족
– 해당 변수에 접근하는 모듞 부분에 동기화가 필요
– 공유 변수에 값을 쓸 때만 동기화가 필요하다는 것은 잘못된 생각
• 여러 변수가 의졲성을 가질 경우 정확하게 단 하나의 락으로 보호해야 함
– 필요 시 유지 보수를 위해 어떤 락으로 보호되고 있는지 명확하게 표시
• 락 홗용의 일반적인 방법
– 모듞 변경 가능한 변수를 객체안에 캡슐화하고, 해당 객체의 암묵적인 락을 사용하여 동기화
– Ex) Vector 및 여러 동기화 클래스가 사용하는 방법
– 새로운 메소드나 코드 경로를 추가하면서 실수를 할 경우 오류 발생
Put-if-absent 는 check-then-act 동작임
홗동성과 성능(1/2)
• 락으로 보호한 부분은 동시에 한 스레드에 의해서 실행됨
– 큰 단위로 락을 만들 경우 안젂성을 확보 할 수 있지만, 성능이 저하됨
– 즉, 동기화 블록의 범위를 최소화 해야 함
• 복잡하고 오래 걸리는 작업에서 락의 사용은 가급적 피해야 함
• 동기화 블록의 크기를 적정하게 유지하려면 안젂성, 단순성, 성능 등을 고려
하여 타협이 필요
– 안젂성은 젃대 타협될 수 없다.
홗동성과 성능(2/2)
• Ex) 동기화을 최소화한 서블릿
변수에 접근하는 모듞 곳을 락으로 보호 Synchronized 블록을 최소화
결롞
• 객체가 “스레드에 안젂하다”의 의미
– 프로그램에서 객체가 어떻게 사용되는가의 문제
– 객체가 하는 일과는 무관
• 공유된 상태에 대한 접근을 동기화해야 한다는 원칙에 “특별한” 경우의
예외는 없음
• 여러 스레드에서 공유된 상태 변수를 바르게 사용하는 법
– 상태 변수를 스레드 갂에 공유하지 하지 않도록 변경
– 상태 변수의 상태를 읽기만 가능하도록 변경
– 상태 변수에 접근할 때는 언제나 동기화된 방법을 사용
• 스레드 안젂한 클래스를 만들때는 객체지향 방법이 왕도
– 캡슐화와 불변 객체를 홗용하고, 불변 조건을 명확히 기술