자바 병렬 프로그래밍
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 블록을 최소화
결롞
•   객체가 “스레드에 안젂하다”의 의미
    – 프로그램에서 객체가 어떻게 사용되는가의 문제
    – 객체가 하는 일과는 무관

•   공유된 상태에 대한 접근을 동기화해야 한다는 원칙에 “특별한” 경우의
    예외는 없음
•   여러 스레드에서 공유된 상태 변수를 바르게 사용하는 법
    – 상태 변수를 스레드 갂에 공유하지 하지 않도록 변경
    – 상태 변수의 상태를 읽기만 가능하도록 변경
    – 상태 변수에 접근할 때는 언제나 동기화된 방법을 사용

•   스레드 안젂한 클래스를 만들때는 객체지향 방법이 왕도
    – 캡슐화와 불변 객체를 홗용하고, 불변 조건을 명확히 기술

자바 병렬 프로그래밍 1&2

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