Thread

Process 와 Thread

ν”„λ‘œμ„ΈμŠ€μ™€ μŠ€λ ˆλ“œλŠ” μ„œλ‘œ λ°€μ ‘ν•œ 관계에 μžˆμœΌλ‚˜ μ„œλ‘œ λ‹€λ₯Έ κ°œμ²΄μ΄λ‹€.

  • Process
    • OS λ‘œλΆ€ν„° μ‹œμŠ€ν…œ μžμ›μ„ ν• λ‹Ήλ°›λŠ” μž‘μ—…μ˜ λ‹¨μœ„
    • CPU μ‹œκ°„μ΄λ‚˜ λ©”λͺ¨λ¦¬ λ“±μ˜ μ‹œμŠ€ν…œ μžμ›μ΄ ν• λ‹Ήλ˜λŠ” 독립적인 개체
    • 각 ν”„λ‘œμ„ΈμŠ€λŠ” λ³„λ„μ˜ μ£Όμ†Œ κ³΅κ°„μ—μ„œ μ‹€ν–‰ 되며, ν•œ ν”„λ‘œμ„ΈμŠ€λŠ” λ‹€λ₯Έ ν”„λ‘œμ„ΈμŠ€μ˜ λ³€μˆ˜λ‚˜ μžλ£Œκ΅¬μ‘°μ— μ ‘κ·Όν•  수 μ—†μŒ
    • 같은 λ©”λͺ¨λ¦¬λ₯Ό 읽고 μ“°λŠ” ν”„λ‘œμ„ΈμŠ€λŠ” 생성 κ°€λŠ₯
    • ν”„λ‘œμ„ΈμŠ€κ°„μ˜ 톡신은 Pipe, Socket, File λ“±μœΌλ‘œ ν†΅μ‹ ν•œλ‹€.
  • Thread
    • ν”„λ‘œμ„ΈμŠ€κ°€ 할당받은 μžμ› 을 μ΄μš©ν•˜λŠ” μ‹€ν–‰ ν˜Ήμ€ νλ¦„μ˜ λ‹¨μœ„
    • ν”„λ‘œμ„ΈμŠ€μ™€ 같은 κ³΅κ°„μ˜ Stack 곡간을 μ‚¬μš©ν•˜λ©° μ—¬λŸ¬ Thread λŠ” κ·Έ μƒνƒœμ˜ 일뢀λ₯Ό κ³΅μœ ν•œλ‹€.
    • Thread λŠ” ν”„λ‘œμ„ΈμŠ€ λ‚΄μ—μ„œ 각각의 Stack 만 λ”°λ‘œ ν• λ‹Ή λ°›κ³  Code Data Heap μ˜μ—­μ€ κ³΅μœ ν•œλ‹€.

ν”„λ‘œμ„ΈμŠ€μ˜ μŠ€λ ˆλ“œ

Thread 의 λŒ€λΆ€λΆ„μ˜ 정보듀은 JVM 에 μ˜ν•΄ κ΄€λ¦¬λœλ‹€.

  • λͺ‡ 개의 Thread κ°€ μ‘΄μž¬ν•˜λŠ”μ§€
  • 싀행쀑인 ν”„λ‘œκ·Έλž¨μ˜ μ½”λ“œμ˜ λ©”λͺ¨λ¦¬ μœ„μΉ˜λŠ” 어디인지
  • ν˜„μž¬ Thread 의 μƒνƒœ
  • Thread 의 μš°μ„ μˆœμœ„ 정보

Thread ꡬ쑰

@TODO

Thread 생λͺ…μ£ΌκΈ°

@TODO

Thread 생성방법

μ•„λž˜μ™€ 같이 크게 3가지 방법이 μžˆλ‹€.

  • Thread 클래슀λ₯Ό ν™•μž₯ ν•œλ‹€.
  • Runnable μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„
  • Thread Pool 을 μƒμ„±ν•˜κΈ° μœ„ν•΄, μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ Executor ν”„λ ˆμž„μ›Œν¬λ₯Ό μ‚¬μš©ν•œλ‹€.

'Runnable' μΈν„°νŽ˜μ΄μŠ€λŠ” 상속 객체λ₯Ό ν•„μš”λ‘œ ν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ— μΈν„°νŽ˜μ΄μŠ€λ‘œ μ μ ˆν•˜λ‹€.

μ΄λŸ¬ν•œ 방법듀은 λŒ€λΆ€λΆ„ λ©€ν‹°μŠ€λ ˆλ“œλ₯Ό λ§Œλ“€μ–΄ μž‘μ—…μ„ μˆ˜ν–‰ν•˜λŠ” κ³Όμ •μœΌλ‘œ λ©€ν‹°μŠ€λ ˆλ“œ μ˜μ—­μ—μ„œ μžμ„Έν•œ 방법듀을 μ†Œκ°œν•œλ‹€.

Thread μƒνƒœ

  • NEW : Thread κ°€ μ‹€ν–‰ μ€€λΉ„κ°€ λ˜μ—ˆμŠ΅λ‹ˆλ‹€.
  • RUNNABLE : JVM (Java Virtual Machine) 이 Thread μ½”λ“œλ₯Ό μˆ˜ν–‰μ€‘μž…λ‹ˆλ‹€.
  • BLOCKED : Thread κ°€ μ°¨λ‹¨λ˜μ–΄ μžˆλŠ” μƒνƒœ μž…λ‹ˆλ‹€.
  • WAITING : Thread λ‹€λ₯Έ Thread 의 μž‘μ—…μ΄ μˆ˜ν–‰λ˜κΈ°λ₯Ό κΈ°λ‹€λ¦½λ‹ˆλ‹€.
  • TIMED_WAITING : Thread κ°€ λ‹€λ₯Έ Thread 의 μ§€μ •λœ λŒ€κΈ°μ‹œκ°„μ˜ νŠΉμ • μž‘μ—…μ„ μˆ˜ν–‰ν•˜κΈ°κΉŒμ§€ κΈ°λ‹€λ¦½λ‹ˆλ‹€.
  • TERMIATED : Thread 의 싀행을 μ™„λ£Œν–ˆμŠ΅λ‹ˆλ‹€.

Multi Thread

ν•˜λ‚˜μ˜ ν”„λ‘œκ·Έλž¨μ„ μ—¬λŸ¬ Thread 둜 κ΅¬μ„±ν•˜κ³  각 Thread 둜 ν•˜μ—¬κΈˆ ν•˜λ‚˜μ˜ μž‘μ—…μ„ μ²˜λ¦¬ν•˜λ„λ‘ ν•˜λŠ” 것

λŒ€ν‘œμ μœΌλ‘œ μ›Ή μ„œλ²„λŠ” Multi Thread Application 이닀.

  • μž₯점
    • μ‹œμŠ€ν…œ μžμ› μ†Œλͺ¨ κ°μ†Œ (μžμ›μ˜ νš¨μœ¨μ„± μ¦λŒ€)
    • μ‹œμŠ€ν…œ μ²˜λ¦¬λŸ‰ 증가
    • ν”„λ‘œκ·Έλž¨λ‚΄μ˜ μ‘λ‹΅μ‹œκ°„ 단좕
  • 단점
    • μ„€κ³„μ˜ λ‚œμ΄λ„κ°€ 높아진닀.
    • 디버깅이 μ–΄λ ΅λ‹€.
    • 단일 ν”„λ‘œμ„ΈμŠ€ μ‹œμŠ€ν…œμ˜ 경우 효과λ₯Ό κΈ°λŒ€ν•  수 μ—†λ‹€.
    • λ‹€λ₯Έ ν”„λ‘œμ„ΈμŠ€μ—μ„œ μŠ€λ ˆλ“œ μ œμ–΄κ°€ μ–΄λ ΅λ‹€.
    • λ™μ‹œμ„± λ¬Έμ œκ°€ λ°œμƒν•œλ‹€.
    • ν•˜λ‚˜μ˜ μŠ€λ ˆλ“œλ‘œ 인해 μ „μ²΄μ˜ ν”„λ‘œμ„ΈμŠ€κ°€ 영ν–₯을 λ°›λŠ”λ‹€.

λ©€ν‹°μŠ€λ ˆλ“œ

Multi Thread ν™˜κ²½μ˜ μž‘μ—…μ‹œμ—λŠ” Therad κ°„μ˜ μžμ› 곡유의 동기화 문제 에 신경을 써야 ν•œλ‹€.

Java μ—μ„œλŠ” Multi Thread ν™˜κ²½μ„ λ§Œλ“€μ–΄ μ‚¬μš©ν•˜λŠ” 방법은 λŒ€ν‘œμ μœΌλ‘œ 3가지 방법을 많이 μ‚¬μš©ν•œλ‹€.

Thread Class λ₯Ό 상속받아 μ‚¬μš©

Thread Class λ₯Ό μ„œλΈŒν΄λž˜μ‹±(subclassing) ν•˜κ³  run Method λ₯Ό Override ν•œλ‹€.

κ΅¬ν˜„ μˆœμ„œ

  1. Thread Class λ₯Ό 상속 λ°›μ•„ λ‚΄κ°€ μ‹œν‚¬ 일을 해쀄 Class λ₯Ό ν•˜λ‚˜ λ§Œλ“ λ‹€.
  2. μœ„μ—μ„œ λ§Œλ“  Class 에 run Method μ•ˆμ— μ‹œν‚¬ 일을 μ •μ˜ν•΄ μ€€λ‹€.
  3. 메인 Thread μ—μ„œ μœ„μ—μ„œ λ§ŒλŠ” Class 의 start Method λ₯Ό ν˜ΈμΆœν•œλ‹€.

λ°˜λ“œμ‹œ start λ©”μ†Œλ“œλ‘œ 싀행을 ν•΄μ•Ό ν•œλ‹€.
run λ©”μ†Œλ“œλ₯Ό μ‹€ν–‰ν•˜λ©΄ 메인 Thread μ—μ„œ λŒμ•„κ°€λ―€λ‘œ μ˜λ―Έκ°€ μ—†λ‹€.

static class AddThread extends Thread {
  @Override
  public void run() {
    int sum = 0;

    for (int i = 1; i < 11; ++i) {
      sum += i;

      System.out.printf("Add Sum is %d\r\n", sum);
    }
  }
}
AddThread at = new AddThread();
at.start();

Runnable μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜μ—¬ μ‚¬μš©

Runnable μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜κ³  Runnable 객체λ₯Ό Thread μƒμ„±μžλ‘œ μ „λ‹¬ν•œλ‹€.

κ΅¬ν˜„μˆœμ„œ

  1. μš°μ„  Runnable Interface λ₯Ό κ΅¬ν˜„ν•  Class λ₯Ό ν•˜λ‚˜ μƒμ„±ν•œλ‹€.
  2. μœ„μ—μ„œ λ§Œλ“  Class 의 run Method 에 μ‹œν‚¬ 일을 μ •μ˜ν•œλ‹€.
  3. ν•΄λ‹Ή Class λ₯Ό μƒμ„±ν•˜κ³  Thread λ₯Ό 생성할 λ•Œ 인자둜 λ„£μ–΄μ„œ μƒμ„±ν•œλ‹€.
  4. 메인 Threadμ—μ„œ μœ„μ—μ„œ λ§Œλ“  Class 의 start Method λ₯Ό ν˜ΈμΆœν•œλ‹€.
static class AddThreadRunnable implements Runnable {
  @Override
  public void run() {
    int sum = 0;

    for (int i = 1; i < 11; ++i) {
      sum += i;

      System.out.printf("Add Sum is Runnable %d\r\n", sum);
    }
  }
}
Runnable ar = new AddThreadRunnable();
Thread atr = new Thread(ar);

atr.start();

Thread κ°€ ν•  일을 run Method μ•ˆμ— λ„£μœΌλ©΄ λœλ‹€.

Single Thread ν”„λ‘œκ·Έλž¨μ€ main Method κ°€ λ°˜ν™˜λ˜λ©΄ μ’…λ£Œλ˜κ³ 
Multi Thread ν”„λ‘œκ·Έλž¨μ€ run Method 의 싀행이 λλ‚˜λ©΄ μ’…λ£Œλœλ‹€.

Future, Callable, Executor

Java 5 μ΄μƒμ—μ„œ μ§€μ›ν•˜λŠ” λ°©μ‹μœΌλ‘œ Callback Pattern 으둜 μ‰½κ²Œ μ‚¬μš© κ°€λŠ₯ν•˜λ„λ‘ ν•˜λŠ” μ ‘κ·Ό 방법이닀.

λ‹€μ–‘ν•œ μ’…λ₯˜μ˜ Thread λ₯Ό μƒμ„±ν•œ λ‹€μŒ, μ—¬λŸ¬ Thread 둜 λΆ€ν„° μ›ν•˜λŠ” μˆœμ„œλŒ€λ‘œ 값을 μ–»μ–΄μ˜¬ 수 μžˆλ‹€.

κ΅¬ν˜„ μˆœμ„œ

  1. μž‘μ—… λŒ€μƒμ˜ Callable 객체λ₯Ό μƒμ„±ν•œ ν›„ ExecutorService 에 λ“±λ‘ν•œλ‹€.
  2. μž‘μ—…μ˜ κ²°κ³ΌλŠ” Future 객체가 λ°˜ν™˜ λ°›λŠ”λ‹€.
  3. Future 객체 μ‚¬μš© μ‹œ 이미 κ²°κ³Όκ°€ μ€€λΉ„ λ˜μ–΄ μžˆλŠ” κ²½μš°μ—λŠ” μ¦‰μ‹œ μ‚¬μš©ν•˜λ©°, 그렇지 μ•ŠλŠ” κ²½μš°μ—λŠ” Polling Thread λŠ” μ€€λΉ„κ°€ 될 λ•ŒκΉŒμ§€ Block μƒνƒœκ°€ λœλ‹€.

Synchronizred

Java μ—μ„œ 동기화 μ˜μ—­μ€ synchronizred ν‚€μ›Œλ“œλ‘œ ν‘œμ‹œλœλ‹€.

λ™κΈ°ν™”λŠ” 객체에 λŒ€ν•œ λ™κΈ°ν™”λ‘œ μ΄λ£¨μ–΄μ§€λŠ”λ° μ—¬λŸ¬ Thread κ°€ ν•œ 개의 μžμ›μ„ μ‚¬μš©ν•˜κ³ μž ν•  λ•Œ ν•΄λ‹Ή Thread 만 μ œμ™Έν•˜κ³  λ‚˜λ¨Έμ§€ Thread 의 접근을 λ§‰λŠ” 방법이닀.
블둝에 접근을 μ‹œλ„ν•˜λŠ” λ‹€λ₯Έ Thread 듀은 블둝 μ•ˆμ˜ Thread κ°€ 싀행을 마치고 블둝을 λ²—μ–΄λ‚ λ•ŒκΉŒμ§€ 차단 (blocked) μƒνƒœ κ°€ λœλ‹€.

λŒ€ν‘œμ μœΌλ‘œ Log Files κ³Ό 같이 μ„œλ‘œ λ‹€λ₯Έ ν”„λ‘œμ„ΈμŠ€μ— μ ‘κ·Ό κ°€λŠ₯ν•œ λ¦¬μ†ŒμŠ€λ₯Ό λŒ€μƒμœΌλ‘œ μ‚¬μš©ν• λ•Œ νš¨κ³Όμ μ΄λ‹€.

μ΄λŸ¬ν•œ 방식을 배타적 μ ‘κ·Ό 이라고 ν•œλ‹€.

μž₯점

  • thread-safe ν•˜κ²Œ μ‚¬μš©μ΄ κ°€λŠ₯ν•˜μ—¬ μ‚¬μš©μžμ˜ μ˜λ„λŒ€λ‘œ ν”„λ‘œκ·Έλž¨μ˜ 흐름 μ œμ–΄κ°€ κ°€λŠ₯ν•˜λ‹€.

단점

  • ν”„λ‘œκ·Έλž¨μ˜ μ„±λŠ₯μ €ν•˜λ₯Ό μΌμœΌν‚¬ 수 μžˆλ‹€.
    • Java λ‚΄λΆ€μ μœΌλ‘œ λ©”μ„œλ“œλ‚˜ λ³€μˆ˜μ— 동기화λ₯Ό ν•˜κΈ° μœ„ν•΄ block & unblock 처리λ₯Ό ν•˜κ²Œλ˜λŠ”λ° 이런 μ²˜λ¦¬λ“€μ„ ν†΅ν•˜μ—¬ μ†ŒλΉ„λ˜λŠ” λ¦¬μ†ŒμŠ€κ°€ ν”„λ‘œκ·Έλž¨ μ „λ°˜μ μΈ μ„±λŠ₯에 영ν–₯을 μ€€λ‹€.

synchronized ν‚€μ›Œλ“œλŠ” λ‹€μŒ 넀가지 μœ ν˜•μ˜ 블둝이 쓰인닀.

Syntax

μΈμŠ€ν„΄μŠ€ λ©”μ†Œλ“œμ— 동기화 적용 (Instance Method)

νŠΉμ • 뢀뢄에 λŒ€ν•΄μ„œλ§Œ 동기화λ₯Ό 동기화λ₯Ό ν•  ν•„μš”κ°€ μžˆμ„ 경우 μ•„λž˜ λ©”μ†Œλ“œμ™€ 같이
선언문에 μžˆλŠ” synchronized ν‚€μ›Œλ“œλ₯Ό ν†΅ν•˜μ—¬ 동기화λ₯Ό ν•œλ‹€.

public synchronized void add(int value) {
  this.count += value;
}

Instance Method 의 λ™κΈ°ν™”λŠ” 이 Method λ₯Ό 가진 Instance (객체) λ₯Ό κΈ°μ€€ 으둜 ν•œλ‹€.
ν•˜λ‚˜μ˜ Class κ°€ λ™κΈ°ν™”λœ Instance Method λ₯Ό 가지면, λ™κΈ°ν™”λŠ” 이 Class 의 ν•˜λ‚˜μ˜ Instance λ₯Ό κΈ°μ€€μœΌλ‘œ 이루어지며 ν•œ μ‹œμ μ— 였직 ν•˜λ‚˜μ˜ Thread 만이 λ™κΈ°ν™”λœ Instance Method λ₯Ό μ‹€ν–‰ν•  수 μžˆλ‹€.

ν•˜λ‚˜μ˜ Instance ν•˜λ‚˜μ˜ Thread 이닀.

정적 λ©”μ†Œλ“œμ— 동기화 적용 (Static Method)

μΈμŠ€ν„΄μŠ€ λ©”μ†Œλ“œμ˜ μ‚¬μš©λ²•κ³Ό 같이 선언문에 μžˆλŠ” synchronized ν‚€μ›Œλ“œλ₯Ό ν†΅ν•˜μ—¬ 동기화λ₯Ό ν•œλ‹€.

public static synchronized void add(int value) {
  count += value;
}

Static Method 의 λ™κΈ°ν™”λŠ” 이 Method λ₯Ό 가진 Class (객체) λ₯Ό κΈ°μ€€ 으둜 ν•œλ‹€.
JVM μ•ˆμ— Class κ°μ²΄λŠ” Class λ‹Ή ν•˜λ‚˜λ§Œ μ‘΄μž¬ν•  수 μžˆμœΌλ―€λ‘œ, 같은 Class 에 λŒ€ν•΄μ„œλŠ” 였직 ν•œ Thread μ—λ§Œ λ™κΈ°ν™”λœ Static Method λ₯Ό μ‹€ν–‰ν•  수 μžˆλ‹€.

ν•˜λ‚˜μ˜ Class λ‹Ή ν•˜λ‚˜μ˜ Thread 이닀.

μΈμŠ€ν„΄μŠ€ λ©”μ†Œλ“œ μ•ˆμ— 동기화 적용 (Instance Method Codeblock)

동기화λ₯Ό λ©”μ†Œλ“œ 전체에 μ μš©ν•˜λŠ”κ²ƒμ΄ μ•„λ‹Œ λ©”μ†Œλ“œμ˜ νŠΉμ • 뢀뢄에 μ μš©ν•˜λŠ”κ²ƒμ΄ 효율적일 λ•Œκ°€ μžˆλ‹€.

public void add(int value) {
  synchronized(this) {
    this.count += value;
  }
}

정적 λ©”μ†Œλ“œμ— μ•ˆμ— 동기화 적용 (Static Method Codeblock)

Instance Method Codeblock κ³Ό μ‚¬μš©λ²•μ€ λ™μΌν•˜λ‹€.

public static void add(int value) {
  synchronized(this) {
    this.count += value;
  }
}

Callable 1.5 vs Runnable 1.0

Callable 은 Runnable 처럼 λ°”λ‘œ Thread 에 인자둜 전달 λΆˆκ°€ν•˜λ©°
ExecutorService 객에체 submit() λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ μ „λ‹¬ν•œλ‹€. (ThreadPool μ‚¬μš©)

ExecutorService mPool = Executors.newFixedThreadPool(5);
Future<String> mFuture = mPool.submit(new Callable<String>() {
  @Override
  public String call() throws Exception {
    Thread.sleep(500);
    return "JustTest";
  }
});

Runnable 은 Callable κ³Ό 달리 Thread 에 λ°”λ‘œ 인자λ₯Ό 전달 κ°€λŠ₯ν•˜λ‹€.

new Thread(new Runnable() {
  @Override
  public void run() {
    Log.d(Tag, "Thread Test");
  }
});
Callable Runnable
Return Generic 으둜 받은 νƒ€μž…μ„ λ°˜ν™˜ void
Exception Exception 을 κ°€μ§ˆμˆ˜ μžˆλ‹€. μ—†μŒ