ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java] Thread_쓰레드
    ■ Back-End/- Java 2019. 5. 15. 00:00

    참고: http://www.yes24.com/Product/goods/24259565

     

    Java의 정석

    최근 7년동안 자바 분야의 베스트 셀러 1위를 지켜온 `자바의 정석`의 최신판. 저자가 카페에서 12년간 직접 독자들에게 답변을 해오면서 초보자가 어려워하는 부분을 잘 파악하고 쓴 책. 뿐만 아니라 기존의 경력자들을 위해 자바의 최신기능(람다와 스트림)을 자세하면서도 깊이있게 설명하고 있다. 저자가 2002년부터 꾸준히 집필해온 책으로 깊이와 세밀함 그리고...

    www.yes24.com

     

    Q. 프로세스란?

    A. 프로세스는 실행 중인 프로그램을 뜻한다.

    프로세스는 데이터, 메모리와 같은 자원과 쓰레드로 구성되어있다.

    프로세스는 최소 1개 이상의 쓰레드가 존재하며, 2개 이상의 쓰레드로 이루어져 있을 때 멀티 쓰레드 프로세스라고 부른다.

     

     

    Q. 코드를 병렬로 실행하려면?

    A. Thread 객체를 이용해 병렬 실행이 가능한 쓰레드를 만든다. 쓰레드를 만드는 방법은 2가지가 있다.

    (1) Thread 클래스를 상속받아 생성

    (2) Runnable 인터페이스를 이용해 생성

    (보통 Runnable 인터페이스를 선호. Java는 다중상속을 지원하지 않기 때문에 Thread 클래스를 상속받으면 다른 클래스를 상속받을 수 없다.)

     

     

    Q. 쓰레드 사이의 공유 상태는 어떻게 관리해야할까?

    A. 여러 쓰레드가 같은 자원을 공유하는 경우에는 임계영역(Critical Section)과 락(Lock)을 이용해 자원을 관리해줘야 한다.

    특정 쓰레드가 락을 소유하고, 동기화된 코드 블록(임계영역)을 수행하는 동안, 다른 쓰레드는 자신의 순서가 돌아와도 락이 없으면 접근할 수 없어 기다려야한다.

     

     

    Q. 쓰레드의 상태에 대해 설명하세요?

    참고: Java의 정석

     

    Q. 쓰레드의 동기화란?

    A. 한 쓰레드가 진행 중인 작업을 다른 쓰레드가 간섭하지 못하게 막는 것을 뜻한다.

     

    멀티쓰레드 프로세스의 경우 여러 쓰레드가 같은 프로세스 내의 자원을 공유해서 작업하기 때문에, 서로의 작업에 영향을 주게 된다.

    자바에서는 sychronized 블럭, 'java.util.concurrent.locks'와 'java.util.concurrent.atomic' 패키지를 통해서 동기화를 구현할 수 있다.

     

    (1) synchronized를 이용한 동기화

    synchronized 키워드를 이용해서 임계 영역을 지정하는 방법이다.

    - 메서드 전체를 임계 영역으로 지정

    예) public synchronized void add() { ... }

    쓰레드는 synchronized 메서드가 호출된 시점부터 해당 메서드가 포함된 객체의 lock을 얻어 작업을 수행하다가 메서드가 종료되면 lock을 반납한다.

     

    - 특정 영역을 임계영역으로 지정

    예) synchronized (객체의 참조변수) { ... } // 객체의 참조변수 : 락을 걸고자 하는 객체를 참조

    synchronized 영역 안에 들어가게 되면 지정된 객체의 lock을 얻게되고, 영역을 벗어나면 lock을 반납한다.

     

    (2) wait(), notify()을 이용한 동기화

    - 이미 다른 쓰레드가 lock을 갖고 있어, lock을 반납할 때까지 기다린다. 나중에 작업을 진행할 수 있는 상황이 되면 notify()를 호출해서 lock을 얻어 작업을 진행한다.

    - 동기화 블록 내에서만 사용할 수 있다.

     

    (+) 기아현상(Starvation) : notify()를 받지 못하고 계속 wait()하는 현상

    (+) 경쟁상태(Race Condition) : 여러 쓰레드가 lock을 얻기 위해 서로 경쟁하는 것.

     

    (3) Lock, Condition을 이용한 동기화

    - 'java.util.concurrent.locks' 패키지가 제공하는 lock 클래스들을 이용하는 방법.

    ReentrantLock

    - 가장 일반적인 lock. 재진입이 가능하다.

    - 특정 조건에서 lock을 풀고 나중에 다시 lock을 얻고 임계영역으로 들어와서 이후의 작업을 수행할 수 있다.

    - 무조건 lock이 있어야만 임계 영역의 코드를 수행할 수 있다.

     

    ReentrantReadWriteLock

    - 읽기를 위한 lock과 쓰기를 위한 lock을 제공한다.

    - 읽기 lock이 걸려있는 경우, 다른 쓰레드가 읽기 lock을 중복해서 읽기를 수행할 수 있다.

     

    StampedLock

    - lock을 걸거나 해지할 때, '스탬프(long 타입의 정수값)'을 사용한다.

    - 읽기와 쓰기를 위한 lock에 '낙관적 읽기 lock'이 추가됨. '낙관적 읽기 lock'은 쓰기 lock에 의해 바로 풀린다. 낙관적 읽기에 실패하면, 읽기 lock을 얻어서 다시 읽어 와야 한다.

     

    - Condition을 이용한 방법

    생성하는 쓰레드와, 소비하는 쓰레드가 있다고 가정했을 때, 두 쓰레드를 구분해서 notify()를 호출할 수 없다. 이 때 사용하는 것이 Condition 이다. 쓰레드별로 각각 Condition을 만들어서 각각의 waiting pool에서 따로 기다리도록 한다. wait()과 notify() 대신 await()와 signal()을 사용한다.

     

    예)

    ReetrantLock lock = new ReentrantLock();

    Condition forProducer = lock.newCondition();

    Condition forCustomer = lock.newCondition();

    ....

    try {

        forProducer.await();   // 생산자만 기다리게 함

    } catch(InterruptedException e) { }

    ...

    forCustomer.signal();     // 소비자만 깨움

    ...

     

     

     

     

     

     

     

     

     

Designed by Tistory.