본문 바로가기

Java/Theory

Chapter 9. Thread

Chapter 9. Thread

1. Process & Thread

 - Process

  · 실행 중인 Program을 지칭하며 Program을 실행 하면 OS로부터 실행에 필요한 자원을 할당받아 Process가 된다.

  · Process는 Program을 수행하는데 필요한 Data, Memory, Resource, Thread로 구성된다.

  · Process 내에는 최소한 하나 이상의 Thread가 존재한다.

  · Process의 Memory 한계(Call Stack의 크기)에 따라 Process 내에 생성할 수 있는 Thread의 수가 결정된다. 

  · Multi-Threaded Process

  ◦ Process 내에 둘 이상의 Thread가 존재하는 Process

  ◦ 여러 Thread가 하나의 Process 내에서 자원을 공유하면서 작업하기 때문에 문제가 발생할 수 있다.

  ◦ 장점

   ▹ CPU의 사용률을 향상시킨다.

   ▹ 자원을 보다 효율적으로 사용할 수 있다.

   ▹ 사용자에 대한 응답성이 향상된다.

   ▹ 작업이 분리되어 Code가 간결해진다.

  ◦ 단점

   ▹ 동기화(Synchronization), 교착상태(Deadlock) 등 자원 공유 문제가 발생할 수 있다.


2. Thread

 - Process 내의 실행 흐름

 - Process 내의 Code, Data를 이용해 Program의 실행을 관리한다.

 - 특징

  · Java에서는 Main Method가 실행되면 하나의 Process가 작업을 진행하며 해당 Thread를 Main Thread라고 한다.

  · Main Thread 하나만 작업을 진행하는 것을 Single-Thread라고 한다.

 - Thread의 구현 & 실행

  · Thread 구현 방법

  ◦ Thread 구현 방법은 두 가지가 있는데 Thread Class를 상속받거나 Runnable Interface를 구현하는 방법이 있다.

  ◦ Thread Class

1
2
3
4
5
6
7
8
9
10
11
public class Thread {
      private Runnable r;
 
      public Thread(Runnable r) {
            this.r = r;
      }
      public void run() {
            if(r!=null)
                  r.run();
      }
}
cs

   ▹ Runnable을 구현한 Class의 Instance를 참조하기 위한 변수를 선언한다.

   ▹ Runnable Interface를 구현한 Instance의 run()을 호출해 사용한다.

  ◦ Thread Class 상속 방법

1
2
3
4
5
class MyThread extends Thread {
      public void run {
            /* 작업 내용 */
      }
}
cs

  ◦ Runnable Interface

1
2
3
public interface Runnable {
      public abstract void run();
}
cs

   ▹ run() Method만 정의되어있는 간단한 Interface

   ▹ Runnable Interface 구현할 경우

1
2
Runnable r = new MyThread();
Thread t = new Thread(r);
cs

    ▸  Runnable Interface를 구현한 Class의 Instance를 생성한 후, 해당 Instance를 Thread Class의 Instance를 생성할 때 생성자의 매개변소로써 넣어줘야 한다.

   ▹ Runnable Interface 구현 방법

1
2
3
4
5
class MyThread implements Runnable {
      public void run {
            /* 작업 내용 */
      }
}
cs

 - run() & start()

  · run()과 start() Method 간의 차이점

  ◦ run()

   ▹ 생성된 Thread를 실행시키는 것이 아니고 단순히 해당 Class의 run() Method 하나를 호출하는 것

  ◦ start()

   ▹ 새로운 Thread가 작업을 실행하기 위해 필요한 Call Stack을 생성한 후 해당 Stack에 run() Method를 호출한다.

   ▹ 호출된 run() Method는 Call Stack에 처음으로 등록되기 때문에 생성된 Call Stack에 첫 번째로 저장된다.

  · start() Method에 의한 run() Method 호출 순서

  ◦ main Method에서 Thread의 start Method 호출

  ◦ start Method는 Thread가 작업을 수행하는데 사용될 새로운 Call Stack 생성

  ◦ 생성된 Call Stack에 Run() Method를 호출해 Thread가 작업을 수행하도록 함

  ◦ Call Stack이 두 개가 되었기 때문에 Scheduler가 정한 순서에 의해서 번갈아 가면서 실행

 - Single-Thread & Multi-Thread

  · Single-Thread

  ◦ 하나의 Thread로 두 개의 작업을 처리하는 경우

  ◦ 한 작업을 마친 후 다른 작업을 수행

  · Multi-Thread

  ◦ 두 개의 Thread로 두 개의 작업을 처리하는 경우

  ◦ 짧은 시간동안 2개의 Thread가 번갈아 가면서 작업을 수행

  · Single-Thread & Multi-Thread 비교

  ◦ 작업 수행 시간을 비교하면 Single-Thread와 Multi-Thread의 작업 수행 시간은 거의 같다.

  ◦ 오히려 작업 전환(Context Switching) 때문에 두 개의 Thread로 작업한 시간이 Single-Thread로 작업한 시간보다 더 걸린다.

  ◦ 따라서 단순히 CPU만을 사용한 계산작업이라면 Single-Thread로 작업하는 것이 효율적이다.

  · Thread의 특징

  ◦ Java는 OS(Platform)에 독립적이지만 일부 종속적인 부분도 존재하며 Thread는 이 종속적인 부분에 해당한다.

  ◦ Multi-Thread의 작업 순서는 OS의 Process Scheduler에 의해 실행할 때마다 다른 결과를 얻게 된다.

 - Priority of Thread

  · Thread는 우선순위(Priority)라는 Member를 가지고 있으며 이 우선순위의 값에 따라 Thread가 얻는 실행시간이 달라진다.

  · 특징

  ◦ Thread 작업 중요도에 따라 Thread의 우선순위를 서로 다르게 지정할 수 있다.

  ◦ Thread의 우선순위는 1~10까지 지정할 수 있으며 숫자가 높을수록 우선순위가 높다.

  ◦ main Method 내의 자동으로 5로 설정된다.

  · Thread 우선순위에 의한 작업

  ◦ Thread의 우선순위를 확인

  ◦ 우선순위에의해 각 Thread에 실행 시간 할당

  ◦ 우선순위를 할당 받은 모든 Thread Scheduler에 의해 각각 할당된 실행 시간만큼만 실행하고 전환

 - Thread Group

  · 서로 관련된 Thread를 Group으로 묶어 관리하기 위한 것

  · 특징

  ◦ Thread Group에는 다른 Thread Group을 포함시킬 수 있다.

  ◦ 모든 Thread는 반드시 Thread Group에 포함되어 있어야 한다.  ◦ Thread Group을 지정하는 생성자를 사용하지 않은 Thread는 기본적으로 자신을 생성한 Thread와 같은 이름을 가진 Thread Group에 속하게 된다.

 - Daemon Thread

  · 일반 Thread의 작업을 돕는 보조적인 역할을 수행하는 Thread

  · 특징

  ◦ 일반 Thread가 모두 종료되면 Daemon Thread 또한 강제적으로 자동 종료된다.

  ◦ 무한 Loop와 조건문을 이용해 실행 후 대기하고 있다가 특정 조건이 만족되면 수행하고 다시 대기하도록 작성된다.

  ◦ 일반 Thread의 작성 방법과 실행 방법이 같으며 Thread를 생성한 후 실행하기 전에 setDaemon(true)를 호출하기만 하면된다.

    ※  현재는 suspend() 대신에 wait()를 resume() 대신에 notify()를 사용하고 있다.

 - Thread 상태

Status

Explain

 NEW

 Thread가 생성되고 아직 start()가 호출되지 않은 상태

 RUNNABLE

 실행 중 또는 실행 가능한 상태

 BLOCKED

 동기화 Block에 의해 일시정지된 상태(lock이 풀릴 때까지 기다리는 상태)

 WAITING, TIMED_WAITING

 Thread의 작업이 종료되지는 않았지만 실행가능하지 않은 일시정지 상태

 TIMED_WAITING은 일시정지시간이 지정된 경우를 의미

 TERMINATED

 Thread의 작업이 종료된 상태

 - 작업 수행에 따른 Thread 상태

  · 단계 1)

  ◦ Thread가 생성하고 start()를 호출하면 바로 실행되는 것이 아니라 실행대기열에 저장되어 자신의 차례가 될 때까지 기다려야한다.

  ◦ 실행 대기열은 Queue와 같은 구조로 먼저 실행대기열에 들어온 Thread가 먼저 실행된다.

  · 단계 2)

  ◦ 실행 대기상태에 있다가 자신의 차례가 되면 실행상태가 된다.

  · 단계 3)

  ◦ 주어진 실행시간이 다되거나 yield()를 만나면 다시 실행대기상태가 되고 다음 차례의 Thread가 실행상태가 된다.

  · 단계 4)

  ◦ 실행중 suspend(), sleep(), wait(), join(), I/O block에 의해 일시정지상태가 될 수 있다.

  ◦ I/O block은 입출력 작업에서 발생하는 지연상태를 말한다.

  ◦ 사용자의 입력을 기다리는 경우 예로 들 수 있는데, 이런 경우 일시정지 상태에 있다가 사용자가 입력을 마치면 다시 실행대기상태가 된다.

  · 단계 5)

  ◦ 지정된 일시정지시간이 다되거나(time-out), notify(), resume(), interrupt()가 호출되면 일시정지 상태를 벗어나 다시 실행대기열에 저장되어 자신의 차례를 기다리게 된다.

  · 단계 6)

  ◦ 실행을 모두 마치거나 stop()이 호출되면 Thread는 소멸된다.

 - Thread 동기화(Synchronization)

  · Multi-Thread Programming에서 중요한 요소로 얼마나 동기화를 잘 처리하는가에 따라서 프로그램의 성능에 많은 영향을 미친다.

  · synchronized를 이용한 동기화

  ◦ 작업과 관련된 공유 Data에 lock을 걸어서 먼저 작업 중이던 Thread가 작업을 완전히 마칠 때까지는 다른 Thread에게 제어권이 넘어가더라도 Data가 변경되지 않도록 보호함으로써 Thread 동기화를 가능하게한다.

  ◦ synchronized를 이용하면 Thread 동기화에는 유용하지만 교착상태(Deadlock)에 빠져 Program이 정상적으로 작동하지 않을 수 있다.

  ◦ synchronized block

   ▹ synchronized block에서 지정된 객체는 synchronized block의 시작부터 lock이 걸렸다가 block이 끝나면 lock이 풀린다.

   ▹ lock이 걸리는 순간부터 해당 객체에는 다른 Thread가 이 객체에 접근할 수 없게 된다.

  ◦ synchronized Method

   ▹ 한 Thread가 synchronized Method를 호출해 수행하고 있으면 해당 Method가 종료될 때까지 다른 Thread가 이 Method를 호추랗여 수행할 수 없게된다.

  ◦ 사용 방법

   ▹ 특정한 객체에 lock을 걸고자할 경우

1
2
3
synchronized ([Reference Variable of Object]) {
      ......
}
cs

   ▹ Method에 lock을 걸고자할 경우

1
2
3
public synchronized void calcSum() {
      ......
}
cs

  · wait() & notify()

  ◦ Thread 동기화 효율을 높이기위해 같이 사용할 수 있는 Method

  ◦ 특징

   ▹ synchronized Keyword를 사용할 떄 한 Thread가 객체에 lock을 걸고 어떤 조건이 만족될 때까지 기다려야하는 경우 해당 Thread를 그대로 두면 해당 객체를 사용하려는 다른 Thread들은 lock이 풀릴 때까지 기다려햐하는 비효율적인 상황이 발생하며 이 상황을 개선하기 위해 wait()와 notify() Method를 사용한다.

   ▹ 모든 객체에서 호출 가능하다.

   ▹ Object에 정의되어 있다.

   ▹ synchronized Block 내에서만 사용 가능하다.

   ▹ 보다 효율적인 동기화를 가능하게 한다.

  ◦ wait()

   ▹ Thread가 호출시 해당 Thread가 걸었던 모든 lock을 풀고 waiting pool에서 기다리게 된다.

  ◦ notify()

   ▹ 객체의 waiting pool에서 벗어나 실행대기 열에서 자신이 실행될 차례를 기다리는 상태가 된다.

   ▹ notify()는 하나의 Thread만을 깨우고 notifyAll()는 모든 Thread를 깨운다.

   ▹ notifyAll()을 사용해 모든 Thread를 실행대기 열에서 대기시키는 것이 안전하다.



'Java > Theory' 카테고리의 다른 글

Chapter 10. AWT & Applet  (0) 2015.09.05
Chapter 8. Useful Classes II  (0) 2015.08.19
Chapter 7. Useful Classes I  (0) 2015.08.19
Chapter 6. Collection Framework  (0) 2015.08.19
Chapter 5. Inner Class  (0) 2015.08.19