์ž๋ฐ”์˜ ์ •์„ - ์“ฐ๋ ˆ๋“œ(Thread)

๋ธ”๋กœ๊ทธ ์˜ฎ๊ฒผ์Šต๋‹ˆ๋‹ค! ๐Ÿก’ integer.blog



์ž๋ฐ”์˜ ์ •์„(๋‚จ๊ถ์„ฑ ์ €) 2๊ถŒ ํ•™์Šต

1. ํ”„๋กœ์„ธ์Šค์™€ ์“ฐ๋ ˆ๋“œ

  • ํ”„๋กœ์„ธ์Šค๋ž€ ์‹คํ–‰์ค‘์ธ ํ”„๋กœ๊ทธ๋žจ์ด๋‹ค.
  • ํ”„๋กœ๊ทธ๋žจ์„ ์‹คํ–‰ํ•˜๋ฉด OS๋กœ๋ถ€ํ„ฐ ์‹คํ–‰์— ํ•„์š”ํ•œ ์ž์›(๋ฉ”๋ชจ๋ฆฌ)๋ฅผ ํ• ๋‹น๋ฐ›์•„ ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋œ๋‹ค.
  • ํ”„๋กœ์„ธ์Šค์˜ ์ž์›์„ ์ด์šฉํ•ด์„œ ์‹ค์ œ๋กœ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์“ฐ๋ ˆ๋“œ๋‹ค.
  • ๋ชจ๋“  ํ”„๋กœ์„ธ์Šค์—๋Š” ์ตœ์†Œํ•œ ํ•˜๋‚˜ ์ด์ƒ์˜ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์กด์žฌํ•œ๋‹ค.
  • ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋ ค๋ฉด ๊ฐœ๋ณ„์ ์ธ ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„(ํ˜ธ์ถœ์Šคํƒ)์ด ํ•„์š”ํ•˜๋‹ค.
  • CPU์˜ ์ฝ”์–ด(core)๊ฐ€ ํ•œ ๋ฒˆ์— ๋‹จ ํ•˜๋‚˜์˜ ์ž‘์—…๋งŒ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ๋™์‹œ์— ์ฒ˜๋ฆฌ๋˜๋Š” ์ž‘์—…์˜ ์ˆ˜๋Š” ์ฝ”์–ด์˜ ๊ฐœ์ˆ˜์™€ ์ผ์น˜ํ•œ๋‹ค.

2. ์“ฐ๋ ˆ๋“œ์˜ ๊ตฌํ˜„๊ณผ ์‹คํ–‰

  • ์“ฐ๋ ˆ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ Thread ํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›๋Š” ๋ฐฉ๋ฒ•๊ณผ Runnable ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.
  • Thread ํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›์œผ๋ฉด ๋‹ค๋ฅธ ํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›์„ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์—, Runnable ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์ผ๋ฐ˜์ ์ด๋‹ค.

2.1. Thread ํด๋ž˜์Šค ์ƒ์†

class MyThread extends Thread {
  public void run() { // Thread ํด๋ž˜์Šค์˜ run()์„ ์˜ค๋ฒ„๋ผ์ด๋”ฉ
    ์ž‘์—… ๋‚ด์šฉ
  }
}

2.2. Runnable ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„

Runnable ์ธํ„ฐํŽ˜์ด์Šค๋Š” ์˜ค๋กœ์ง€ run()๋งŒ ์ •์˜๋˜์–ด ์žˆ๋Š” ๊ฐ„๋‹จํ•œ ์ธํ„ฐํŽ˜์ด์Šค์ด๋‹ค.
Runnable ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด์„œ ํ•ด์•ผ ํ•  ์ผ์€ ์ถ”์ƒ๋ฉ”์„œ๋“œ์ธ run()์˜ ๋ชธํ†ต {}์„ ๋งŒ๋“ค์–ด ์ฃผ๋Š” ๊ฒƒ ๋ฟ์ด๋‹ค.

public interface Runnable {
  public abstract void run();
}

์“ฐ๋ ˆ๋“œ๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค๋Š” ๊ฒƒ์€ ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ• ๋ชจ๋‘, ๊ทธ์ € ์“ฐ๋ ˆ๋“œ๋ฅผ ํ†ตํ•ด ์ž‘์—…ํ•˜๊ณ ์ž ํ•˜๋Š” ๋‚ด์šฉ์œผ๋กœ run()์˜ ๋ชธํ†ต{}์„ ์ฑ„์šฐ๋Š” ๊ฒƒ ๋ฟ์ด๋‹ค.

2.3. ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ ๋ฐฉ๋ฒ•

  • Thread ํด๋ž˜์Šค ์ƒ์†
  ThreadA t1 = new ThreadA();
  • Runnable ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„
  Runnable r = new ThreadB();
  Thread t2 = new Thread(r);

Threadํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›์œผ๋ฉด, ์ž์† ํด๋ž˜์Šค์—์„œ ์กฐ์ƒ์ธ Threadํด๋ž˜์Šค์˜ ๋ฉ”์„œ๋“œ๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์ง€๋งŒ,
Runnable์„ ๊ตฌํ˜„ํ•˜๋ฉด Threadํด๋ž˜์Šค์˜ static๋ฉ”์„œ๋“œ์ธ currentThread()๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์“ฐ๋ ˆ๋“œ์— ๋Œ€ํ•œ ์ฐธ์กฐ๋ฅผ ์–ป์–ด ์™€์•ผ๋งŒ ํ˜ธ์ถœ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

class ThreadA extends Thread  {
  public void run() {
    System.out.println(getName());  // ์กฐ์ƒ์ธ Thread์˜ getName() ํ˜ธ์ถœ
  }
}
class ThreadB implements Runnable {
  public void run() {
    System.out.println(Thread.currentThread().getName());
    // Thread.currentThread() - ํ˜„์žฌ ์‹คํ–‰์ค‘์ธ Thread ๋ฐ˜ํ™˜
  }
}

2.4. ์“ฐ๋ ˆ๋“œ์˜ ์‹คํ–‰

  • ์“ฐ๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ–ˆ๋‹ค๊ณ  ์ž๋™์„ ์‹คํ–‰๋˜์ง€ ์•Š๋Š”๋‹ค. start()๋ฅผ ํ˜ธ์ถœํ•ด์•ผ๋งŒ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์‹คํ–‰๋œ๋‹ค.
  • start()๊ฐ€ ํ˜ธ์ถœ๋˜์–ด๋„ ๋ฐ”๋กœ ์‹คํ–‰๋˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ์‹คํ–‰๋Œ€๊ธฐ ์ƒํƒœ์— ์žˆ๋‹ค๊ฐ€ ์ž์‹ ์˜ ์ฐจ๋ก€๊ฐ€ ๋˜์–ด์•ผ ์‹คํ–‰๋œ๋‹ค.
  • ์“ฐ๋ ˆ๋“œ์˜ ์‹คํ–‰ ์ˆœ์„œ๋Š” OS์˜ ์Šค์ผ€์ฅด๋Ÿฌ๊ฐ€ ์ž‘์„ฑํ•œ ์Šค์ผ€์ฅด์— ์˜ํ•ด ๊ฒฐ์ •๋œ๋‹ค.
  • ํ•œ ๋ฒˆ ์‹คํ–‰์ด ์ข…๋ฃŒ๋œ ์“ฐ๋ ˆ๋“œ๋Š” ๋‹ค์‹œ ์‹คํ–‰ํ•  ์ˆ˜ ์—†๋‹ค. (ํ•˜๋‚˜์˜ ์“ฐ๋ ˆ๋“œ์— start()๊ฐ€ ํ•œ ๋ฒˆ๋งŒ ํ˜ธ์ถœ๋  ์ˆ˜ ์žˆ๋‹ค.)

2.5. Start() ์™€ run()

  • main๋ฉ”์„œ๋“œ์—์„œ run()์„ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์€ ์ƒ์„ฑ๋œ ์“ฐ๋ ˆ๋“œ๋ฅผ ์‹คํ–‰์‹œํ‚ค๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ๋‹จ์ˆœํžˆ ํด๋ž˜์Šค์— ์„ ์–ธ๋œ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ผ ๋ฟ์ด๋‹ค.
  • start()๋Š” ์ƒˆ๋กœ์šด ์“ฐ๋ ˆ๋“œ๋ฅผ ์œ„ํ•ด ํ˜ธ์ถœ์Šคํƒ(call stack)์„ ์ƒ์„ฑํ•œ ํ›„์— run()์„ ํ˜ธ์ถœํ•ด์„œ, ์ƒ์„ฑ๋œ ํ˜ธ์ถœ์Šคํƒ์— run()์ด ์ฒซ ๋ฒˆ์งธ๋กœ ์˜ฌ๋ผ๊ฐ€๊ฒŒ ํ•œ๋‹ค.
    1. main๋ฉ”์„œ๋“œ์—์„œ ์“ฐ๋ ˆ๋“œ์˜ start()๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.
    2. start()๋Š” ์ƒˆ๋กœ์šด ์“ฐ๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ž‘์—…ํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋  ํ˜ธ์ถœ์Šคํƒ์„ ์ƒ์„ฑํ•œ๋‹ค.
    3. ์ƒˆ๋กœ ์ƒ์„ฑ๋œ ํ˜ธ์ถœ์Šคํƒ์— run()์ด ํ˜ธ์ถœ๋˜์–ด, ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋…๋ฆฝ๋œ ๊ณต๊ฐ„์—์„œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.
    4. ํ˜ธ์ถœ์Šคํƒ์ด 2๊ฐœ๊ฐ€ ๋˜์—ˆ์œผ๋ฏ€๋กœ ์Šค์ผ€์ฅด๋Ÿฌ๊ฐ€ ์ •ํ•œ ์ˆœ์„œ์— ์˜ํ•ด ๋ฒˆ๊ฐˆ์•„ ๊ฐ€๋ฉด์„œ ์‹คํ–‰๋œ๋‹ค.
  • ์ฃผ์–ด์ง„ ์‹œ๊ฐ„๋™์•ˆ ์ž‘์—…์„ ๋งˆ์น˜์ง€ ๋ชปํ•œ ์“ฐ๋ ˆ๋“œ๋Š” ๋‹ค์‹œ ์ž์‹ ์˜ ์ฐจ๋ก€๊ฐ€ ๋Œ์•„์˜ฌ ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ ์ƒํƒœ๋กœ ์žˆ๋Š”๋‹ค.
  • ์ž‘์—…์„ ๋งˆ์นœ ์“ฐ๋ ˆ๋“œ, ์ฆ‰ run()์˜ ์ˆ˜ํ–‰์ด ์ข…๋ฃŒ๋œ ์“ฐ๋ ˆ๋“œ๋Š” ์‚ฌ์šฉํ•˜๋˜ ํ˜ธ์ถœ์Šคํƒ์ด ๋ชจ๋‘ ๋น„์›Œ์ง€๊ณ  ์‚ฌ๋ผ์ง„๋‹ค.
    • ์ด๋Š” ์ž๋ฐ”ํ”„๋กœ๊ทธ๋žจ์„ ์‹คํ–‰ํ•˜๋ฉด ํ˜ธ์ถœ์Šคํƒ์ด ์ƒ์„ฑ๋˜๊ณ  main๋ฉ”์„œ๋“œ๊ฐ€ ์ฒ˜์Œ์œผ๋กœ ํ˜ธ์ถœ๋˜๊ณ , main๋ฉ”์„œ๋“œ๊ฐ€ ์ข…๋ฃŒ๋˜๋ฉด ํ˜ธ์ถœ์Šคํƒ์ด ๋น„์›Œ์ง€๋ฉด์„œ ํ”„๋กœ๊ทธ๋žจ๋„ ์ข…๋ฃŒ๋˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™๋‹ค.
  • ํ•œ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•ด์„œ ์ข…๋ฃŒ๋˜์–ด๋„ ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ์˜ ์‹คํ–‰์—๋Š” ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š๋Š”๋‹ค.

3. ์“ฐ๋ ˆ๋“œ์˜ ์‹คํ–‰์ œ์–ด

3.1. sleep(long millis)

์ผ์ • ์‹œ๊ฐ„๋™์•ˆ ์“ฐ๋ ˆ๋“œ๋ฅผ ๋ฉˆ์ถ”๊ฒŒ ํ•œ๋‹ค.

static void sleep(long millis)
static void sleep(long millis, int nanos)
  • sleep()์— ์˜ํ•ด ์ผ์‹œ์ •์ง€ ์ƒํƒœ๊ฐ€ ๋œ ์“ฐ๋ ˆ๋“œ๋Š” ์ง€์ •๋œ ์‹œ๊ฐ„์ด ์ง€๋‚˜๊ฑฐ๋‚˜, interrupt()๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด, InterruptedException์ด ๋ฐœ์ƒ๋˜์–ด ์ž ์—์„œ ๊นจ์–ด๋‚˜ ์‹คํ–‰๋Œ€๊ธฐ ์ƒํƒœ๊ฐ€ ๋œ๋‹ค.
  • ๊ทธ๋ž˜์„œ sleep()์„ ํ˜ธ์ถœํ•  ๋•Œ๋Š” ํ•ญ์ƒ try-catch๋ฌธ์œผ๋กœ ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•ด์ค˜์•ผ ํ•œ๋‹ค.
  void delay(long millis) {
    try {
      Thread.sleep(millis);
    } catch(InterruptedException e) {}
  }
  • sleep()์€ ํ•ญ์ƒ ์‹คํ–‰์ค‘์ธ ์“ฐ๋ ˆ๋“œ์— ๋Œ€ํ•ด ์ž‘๋™ํ•œ๋‹ค.
  • ๊ทธ๋ž˜์„œ sleep()์€ static์œผ๋กœ ์„ ์–ธ๋˜์–ด ์žˆ์œผ๋ฉฐ,
    th1.sleep(2000) ์ฒ˜๋Ÿผ ์ฐธ์กฐ๋ณ€์ˆ˜๋ฅผ ์ด์šฉํ•ด์„œ ํ˜ธ์ถœํ•˜๊ธฐ ๋ณด๋‹ค๋Š” Thread.sleep(2000)๊ณผ ๊ฐ™์ด ํ•ด์•ผํ•œ๋‹ค.

3.2. interrupt()์™€ interrupted()

์“ฐ๋ ˆ๋“œ์˜ ์ž‘์—…์„ ์ทจ์†Œํ•œ๋‹ค.

void interrupt()  // ์“ฐ๋ ˆ๋“œ์˜ interrupted ์ƒํƒœ๋ฅผ false์—์„œ true๋กœ ๋ณ€๊ฒฝ
boolean isInterrupted() // ์“ฐ๋ ˆ๋“œ์˜ interrupted์ƒํƒœ๋ฅผ ๋ฐ˜ํ™˜
static boolean interrupted()  // ํ˜„์žฌ ์“ฐ๋ ˆ๋“œ์˜ interrupted์ƒํƒœ๋ฅผ ๋ฐ˜ํ™˜ ํ›„, false๋กœ ๋ณ€๊ฒฝ
  • interrupt()๋Š” ์“ฐ๋ ˆ๋“œ์—๊ฒŒ ์ž‘์—…์„ ๋ฉˆ์ถ”๋ผ๊ณ  ์š”์ฒญํ•œ๋‹ค. (๊ฐ•์ œ ์ข…๋ฃŒ๋Š” ์•„๋‹ˆ๋‹ค.)
  • interrupted()๋Š” ์“ฐ๋ ˆ๋“œ์— ๋Œ€ํ•ด interrupt()๊ฐ€ ํ˜ธ์ถœ๋˜์—ˆ๋Š”์ง€ ์•Œ๋ ค์ค€๋‹ค. (์•Š์•˜๋‹ค๋ฉด false, ํ˜ธ์ถœ ๋˜์—ˆ๋‹ค๋ฉด true ๋ฐ˜ํ™˜)
  • ์“ฐ๋ ˆ๋“œ๊ฐ€ sleep(), wait(), join()์— ์˜ํ•ด ์ผ์‹œ์ •์ง€(waiting) ์ƒํƒœ์— ์žˆ์„ ๋•Œ, ํ•ด๋‹น ์“ฐ๋ ˆ๋“œ์— ๋Œ€ํ•ด interrupt()๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด
    sleep(), wait(), join()์—์„œ Interrupted Exception์ด ๋ฐœ์ƒํ•˜๊ณ  ์“ฐ๋ ˆ๋“œ๋Š” ์‹คํ–‰๋Œ€๊ธฐ(Runnable) ์ƒํƒœ๋กœ ๋ฐ”๋€๋‹ค.
    ์ฆ‰, ๋ฉˆ์ถฐ์žˆ๋˜ ์“ฐ๋ ˆ๋“œ๋ฅผ ๊นจ์›Œ์„œ ์‹คํ–‰๊ฐ€๋Šฅํ•œ ์ƒํƒœ๋กœ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด๋‹ค.

3.3. suspend(), resume(), stop()

๋ชจ๋‘ deprecated ๋œ ๋ฉ”์„œ๋“œ ๋“ค์ด๋‹ค. - suspend()๋Š” sleep()์ฒ˜๋Ÿผ ์“ฐ๋ ˆ๋“œ๋ฅผ ๋ฉˆ์ถ”๊ฒŒ ํ•œ๋‹ค. suspend()์— ์˜ํ•ด ์ •์ง€๋œ ์“ฐ๋ ˆ๋“œ๋Š” resume()์„ ํ˜ธ์ถœํ•ด์•ผ ๋‹ค์‹œ ์‹คํ–‰๋Œ€๊ธฐ ์ƒํƒœ๊ฐ€ ๋œ๋‹ค. - stop()์€ ํ˜ธ์ถœ๋˜๋Š” ์ฆ‰์‹œ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ข…๋ฃŒ๋œ๋‹ค. - suspend()์™€ stop()์€ ๊ต์ฐฉ์ƒํƒœ(Deadlock)๋ฅผ ์ผ์œผํ‚ค๊ธฐ ์‰ฌ์šฐ๋ฏ€๋กœ ๊ถŒ์žฅ๋˜์ง€ ์•Š๋Š”๋‹ค.

3.4. yield()

์“ฐ๋ ˆ๋“œ ์ž์‹ ์—๊ฒŒ ์ฃผ์–ด์ง„ ์‹คํ–‰์‹œ๊ฐ„์„ ๋‹ค์Œ ์ฐจ๋ก€์˜ ์“ฐ๋ ˆ๋“œ์—๊ฒŒ ์–‘๋ณดํ•œ๋‹ค.

3.5. join()

์“ฐ๋ ˆ๋“œ ์ž์‹ ์ด ํ•˜๋˜ ์ž‘์—…์„ ์ž ์‹œ ๋ฉˆ์ถ”๊ณ  ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ง€์ •๋œ ์‹œ๊ฐ„ ๋™์•ˆ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋„๋ก ํ•  ๋•Œ join()์„ ์‚ฌ์šฉํ•œ๋‹ค.

void join()
void join(long millis)
void join(long millis, int nanos)
  • ์‹œ๊ฐ„์„ ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด, ํ•ด๋‹น ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ž‘์—…์„ ๋ชจ๋‘ ๋งˆ์น  ๋•Œ ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๊ฒŒ ๋œ๋‹ค.
  • ์ž‘์—… ์ค‘์— ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ์˜ ์ž‘์—…์ด ๋จผ์ € ์ˆ˜ํ–‰๋˜์–ด์•ผ ํ•  ํ•„์š”๊ฐ€ ์žˆ์„ ๋•Œ join()์„ ์‚ฌ์šฉํ•œ๋‹ค.
  • join()์ด ํ˜ธ์ถœ๋˜๋Š” ๋ถ€๋ถ„์„ try-catch๋กœ ๊ฐ์‹ธ์•ผํ•œ๋‹ค.
  • sleep()๊ณผ ๋‹ค๋ฅธ ์ ์€ join()์€ ํ˜„์žฌ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์•„๋‹Œ ํŠน์ • ์“ฐ๋ ˆ๋“œ์— ๋Œ€ํ•ด ๋™์ž‘ํ•˜๋ฏ€๋กœ static๋ฉ”์„œ๋“œ๊ฐ€ ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์ด๋‹ค.
try {
  th1.join(); // ํ˜„์žฌ ์‹คํ–‰์ค‘์ธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์“ฐ๋ ˆ๋“œ th1์˜ ์ž‘์—…์ด ๋๋‚ ๋•Œ ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.
} catch(InterruptedException e) {}

4. ์“ฐ๋ ˆ๋“œ์˜ ๋™๊ธฐํ™”

ํ•œ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ง„ํ–‰ ์ค‘์ธ ์ž‘์—…์„ ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๊ฐ„์„ญํ•˜์ง€ ๋ชปํ•˜๋„๋ก ๋ง‰๋Š” ๊ฒƒ.

4.1. ์ž„๊ณ„์˜์—ญ(critical section)๊ณผ ์ž ๊ธˆ(lock)

๊ณต์œ  ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ฝ”๋“œ ์˜์—ญ์„ ์ž„๊ณ„์˜์—ญ์œผ๋กœ ์ง€์ •ํ•ด๋†“๊ณ ,
๊ณต์œ  ๋ฐ์ดํ„ฐ(๊ฐ์ฒด)๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” lock์„ ํš๋“ํ•œ ๋‹จ ํ•˜๋‚˜์˜ ์“ฐ๋ ˆ๋“œ๋งŒ ์ด ์˜์—ญ ๋‚ด์˜ ์ฝ”๋“œ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค.
๊ทธ๋ฆฌ๊ณ  ํ•ด๋‹น ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ž„๊ณ„์˜์—ญ ๋‚ด์˜ ๋ชจ๋“  ์ฝ”๋“œ๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ณ  ๋ฒ—์–ด๋‚˜์„œ lock์„ ๋ฐ˜๋‚ฉํ•ด์•ผ
๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋ฐ˜๋‚ฉ๋œ lock์„ ํš๋“ํ•˜์—ฌ ์ž„๊ณ„ ์˜์—ญ์˜ ์ฝ”๋“œ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

4.2. Synchronized๋ฅผ ์ด์šฉํ•œ ๋™๊ธฐํ™”

์ž„๊ณ„์˜์—ญ์„ ์„ค์ •ํ•˜๋Š”๋ฐ ์‚ฌ์šฉ

1. ๋ฉ”์„œ๋“œ ์ „์ฒด๋ฅผ ์ž„๊ณ„ ์˜์—ญ์œผ๋กœ ์ง€์ •
  public synchronized void calcSum()  {
    ...
  }
  
2. ํŠน์ •ํ•œ ์˜์—ญ์„ ์ž„๊ณ„ ์˜์—ญ์œผ๋กœ ์ง€์ •
  synchronized(๊ฐ์ฒด์˜ ์ฐธ์กฐ๋ณ€์ˆ˜)  {
    ...
  }

์“ฐ๋ ˆ๋“œ๋Š” synchronized๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋œ ์‹œ์ ๋ถ€ํ„ฐ ํ•ด๋‹น ๋ฉ”์„œ๋“œ๊ฐ€ ํฌํ•จ๋œ ๊ฐ์ฒด์˜ lock์„ ์–ป์–ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋‹ค๊ฐ€ ๋ฉ”์„œ๋“œ๊ฐ€ ์ข…๋ฃŒ๋˜๋ฉด lock ๋ฐ˜ํ™˜ํ•œ๋‹ค.
lock์˜ ํš๋“๊ณผ ๋ฐ˜๋‚ฉ์ด ๋ชจ๋‘ ์ž๋™์œผ๋กœ ์ด๋ฃจ์–ด์ง€๋ฏ€๋กœ, ๊ฐœ๋ฐœ์ž๋Š” ๊ทธ์ € ์ž„๊ณ„์˜์—ญ๋งŒ ์„ค์ •ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

๋ชจ๋“  ๊ฐ์ฒด๋Š” lock์„ ํ•˜๋‚˜์”ฉ ๊ฐ€์ง€๊ณ  ์žˆ๊ณ , ํ•ด๋‹น ๊ฐ์ฒด์˜ lock์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ์“ฐ๋ ˆ๋“œ๋งŒ ์ž„๊ณ„์˜์—ญ์˜ ์ฝ”๋“œ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋•Œ๋ฌธ์— ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๋“ค์€ lock์„ ์–ป์„ ๋•Œ ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๊ฒŒ ๋˜๋ฏ€๋กœ,

๊ฐ€๋Šฅํ•˜๋ฉด ๋ฉ”์„œ๋“œ ์ „์ฒด์— lock์„ ๊ฑฐ๋Š” ๊ฒƒ ๋ณด๋‹ค, synchronized๋ธ”๋Ÿญ์œผ๋กœ ์ž„๊ณ„์˜์—ญ์„ ์ตœ์†Œํ™”ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

4.3. wait()๊ณผ notify()

๋™๊ธฐํ™”๋œ ์ž„๊ณ„์˜์—ญ์˜ ์ฝ”๋“œ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋‹ค๊ฐ€ ์ž‘์—…์„ ๋” ์ด์ƒ ์ง„ํ–‰ํ•  ์ƒํ™ฉ์ด ์•„๋‹ˆ๋ฉด,
wait()์„ ํ˜ธ์ถœํ•˜์—ฌ ์“ฐ๋ ˆ๋“œ๊ฐ€ lock์„ ๋ฐ˜๋‚ฉํ•˜๊ณ  ๊ธฐ๋‹ค๋ฆฌ๊ฒŒ ํ•œ๋‹ค.
๊ทธ๋Ÿฌ๋ฉด ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๊ฐ€ lock์„ ์–ป์–ด ํ•ด๋‹น ๊ฐ์ฒด์— ๋Œ€ํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.
๋‚˜์ค‘์— ์ž‘์—…์„ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ์ƒํ™ฉ์ด ๋˜๋ฉด notify()๋ฅผ ํ˜ธ์ถœํ•ด์„œ,
์ž‘์—…์„ ์ค‘๋‹จํ–ˆ๋˜ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋‹ค์‹œ lock์„ ์–ป์–ด ์ž‘์—…์„ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค.

wait(), notify(), notifyAll()
  - ํŠน์ • ๊ฐ์ฒด์— ๋Œ€ํ•œ ๊ฒƒ์ด๋ฏ€๋กœ Objectํด๋ž˜์Šค์— ์ •์˜๋˜์–ด ์žˆ๋‹ค.
  - ๋™๊ธฐํ™” ๋ธ”๋ก(synchronized)๋‚ด์—์„œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
  void wait() // notify() ๋˜๋Š” notifyAll()์„ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.
  void wait(long timeout)
  void wait(long timeout, int nanos)  // ์ง€์ •๋œ ์‹œ๊ฐ„๋™์•ˆ๋งŒ ๊ธฐ๋‹ค๋ฆฐ๋‹ค. (์‹œ๊ฐ„ ์ง€๋‚˜๋ฉด ์ž๋™์œผ๋กœ notify()๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™๋‹ค
  void notify()
  void notifyAll()
  • waiting pool์€ ๊ฐ์ฒด๋งˆ๋‹ค ์กด์žฌํ•˜๋ฏ€๋กœ notifyAll()์ด ํ˜ธ์ถœ๋œ๋‹ค๊ณ  ๋ชจ๋“  ๊ฐ์ฒด์˜ waiting pool์— ์žˆ๋Š” ์“ฐ๋ ˆ๋“œ๊ฐ€ ๊นจ์›Œ์ง€๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค.
  • ํ˜ธ์ถœ๋œ ๊ฐ์ฒด์˜ waiting pool์— ๋Œ€๊ธฐ ์ค‘์ธ ์“ฐ๋ ˆ๋“œ๋งŒ ํ•ด๋‹นํ•œ๋‹ค.

4.4. Lock๊ณผ Condition์„ ์ด์šฉํ•œ๋™๊ธฐํ™”

๋™๊ธฐํ™”ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์€ synchronized๋ธ”๋Ÿญ ์™ธ์—๋„ java.util.concurrent.locks ํŒจํ‚ค์ง€๊ฐ€ ์ œ๊ณตํ•˜๋Š” lockํด๋ž˜์Šค๋“ค์„ ์ด์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.
๊ฐ™์€ ๋ฉ”์„œ๋“œ ๋‚ด์—์„œ๋งŒ lock์„ ๊ฑธ ์ˆ˜ ์žˆ๋Š” synchronized๋ธ”๋Ÿญ์˜ ์ œ์•ฝ์ด ๋ถˆํŽธํ•  ๋•Œ lockํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

4.5. Lock

lockํด๋ž˜์Šค์˜ ์ข…๋ฅ˜ 3๊ฐ€์ง€

  • ReentrantLock
    • ์žฌ์ง„์ž…์ด ๊ฐ€๋Šฅํ•œ lock. ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ธ ๋ฐฐํƒ€ lock
    • ํŠน์ • ์กฐ๊ฑด์—์„œ lock์„ ํ’€๊ณ  ๋‚˜์ค‘์— ๋‹ค์‹œ lock์„ ์–ป๊ณ  ์ž„๊ณ„์˜์—ญ์œผ๋กœ ๋“ค์–ด์™€์„œ ์ดํ›„์˜ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ReentrantReadWriteLock
    • ์ฝ๊ธฐ์—๋Š” ๊ณต์œ ์ , ์“ฐ๊ธฐ์—๋Š” ๋ฐฐํƒ€์ ์ธ lock
    • ์ฝ๊ธฐ lock์ด ๊ฑธ๋ฆฐ ์ƒํƒœ์—์„œ ์“ฐ๊ธฐ lock์„ ๊ฑฐ๋Š” ๊ฒƒ์€ ํ—ˆ์šฉ๋˜์ง€ ์•Š๋Š”๋‹ค. (vice versa)
  • StampLock
    • ReentrantReadWriteLock์— ๋‚™๊ด€์  ์ฝ๊ธฐ lock์„ ์ถ”๊ฐ€ํ–ˆ๋‹ค.
    • JDK1.8๋ถ€ํ„ฐ ์ถ”๊ฐ€๋˜์—ˆ์œผ๋ฉฐ, ๋‹ค๋ฅธ lock๊ณผ ๋‹ฌ๋ฆฌ Lock์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์•˜๋‹ค.
    • lock์„ ๊ฑธ๊ฑฐ๋‚˜ ํ•ด์ง€ํ•  ๋•Œ ์Šคํƒฌํ”„(longํƒ€์ž…์˜ ์ •์ˆ˜๊ฐ’)๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
    • ๋ฌด์กฐ๊ฑด ์ฝ๊ธฐ lock์„ ๊ฑธ์ง€ ์•Š๊ณ , ์“ฐ๊ธฐ์™€ ์ฝ๊ธฐ๊ฐ€ ์ถฉ๋Œํ•  ๋•Œ๋งŒ ์“ฐ๊ธฐ๊ฐ€ ๋๋‚œ ํ›„์— ์ฝ๊ธฐ lock์„ ๊ฑฐ๋Š” ๊ฒƒ์ด๋‹ค.

์ผ๋ฐ˜์ ์ธ StampLock์„ ์ด์šฉํ•œ ๋‚™๊ด€์  ์ฝ๊ธฐ์˜ ์˜ˆ

int getBalance()  {
  long stamp = lock.tryOptimisticRead();  // ๋‚™๊ด€์  ์ฝ๊ธฐ lock์„ ๊ฑด๋‹ค.
  int curBalance = this.balance;  // ๊ณต์œ  ๋ฐ์ดํ„ฐ์ธ balance๋ฅผ ์ฝ์–ด ์˜จ๋‹ค.
  
  if(lock.validate(stamp))  { // ์“ฐ๊ธฐ lock์— ์˜ํ•ด ๋‚™๊ด€์  ์ฝ๊ธฐ lock์ด ํ’€๋ ธ๋Š”์ง€ ํ™•์ธ
    stamp = lock.readLock();  // lock์ด ํ’€๋ ธ์œผ๋ฉด, ์ฝ๊ธฐ lock์„ ์–ป์œผ๋ ค๊ณ  ๊ธฐ๋‹ค๋ฆฐ๋‹ค.
    
    try {
      curBalance = this.balance;  // ๊ณต์œ  ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค์‹œ ์ฝ์–ด์˜จ๋‹ค.
    }finally {
      lock.unlockRead(stamp); // ์ฝ๊ธฐ lock์„ ํ‘ผ๋‹ค.
    }
  }
  return curBalance;  // ๋‚™๊ด€์  ์ฝ๊ธฐ lock์ด ํ’€๋ฆฌ์ง€ ์•Š์•˜์œผ๋ฉด ๊ณง๋ฐ”๋กœ ์ฝ์–ด์˜จ ๊ฐ’์„ ๋ฐ˜ํ™˜
}

์ž๋™์œผ๋กœ lock์˜ ์ž ๊ธˆ๊ณผ ํ•ด์ œ๊ฐ€ ๊ด€๋ฆฌ๋˜๋Š” synchronized๋ธ”๋Ÿญ๊ณผ ๋‹ฌ๋ฆฌ,
ReentrantLock๊ณผ ๊ฐ™์€ lockํด๋ž˜์Šค๋“ค์€ ์ˆ˜๋™์œผ๋กœ lock์„ ์ž ๊ทธ๊ณ  ํ•ด์ œํ•ด์•ผ ํ•œ๋‹ค.

์ž„๊ณ„ ์˜์—ญ ๋‚ด์—์„œ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฑฐ๋‚˜ return๋ฌธ์œผ๋กœ ๋น ์ ธ๋‚˜๊ฐ€๊ฒŒ ๋˜๋ฉด lock์ด ํ’€๋ฆฌ์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ unlock()์€ try-finally ๋ฌธ์œผ๋กœ ๊ฐ์‹ธ๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜ ์ ์ด๋‹ค.

lock.lock();  //ReentrantLock lock = enw ReentrantLock();
try {
  // ์ž„๊ณ„์˜์—ญ
} finally {
  lock.unlock();
}

4.6. Condition

wait()๊ณผ notify()๋กœ ์“ฐ๋ ˆ๋“œ์˜ ์ข…๋ฅ˜๋ฅผ ๊ตฌ๋ถ„ํ•˜์ง€ ์•Š๊ณ , ๊ณต์œ  ๊ฐ์ฒด์˜ waiting pool์— ๊ฐ™์ด ๋ชฐ์•„ ๋„ฃ๋Š” ๋Œ€์‹ , ๊ฐ ์“ฐ๋ ˆ๋“œ๋ฅผ ์œ„ํ•œ Condition์„ ๊ฐ๊ฐ ๋งŒ๋“ค์–ด์„œ๊ฑฐ ๊ฐ๊ฐ์˜ waiting pool์—์„œ ๋”ฐ๋กœ ๊ธฐ๋‹ค๋ฆฌ๋„๋ก ํ•œ๋‹ค.

Condition์€ ์ด๋ฏธ ์ƒ์„ฑ๋œ lock์œผ๋กœ๋ถ€ํ„ฐ newCondition()์„ ํ˜ธ์ถœํ•ด์„œ ์ƒ์„ฑํ•œ๋‹ค.

private ReentrantLock lock = new ReentrantLock(); // lock์„ ์ƒ์„ฑ
// lock์œผ๋กœ condition์„ ์ƒ์„ฑ
private Condition forCook = lock.newCondition();
private Condition forCust = lock.newCondition();

wait()๊ณผ notify() ๋Œ€์‹  Condition์˜ await()๊ณผ signal()์„ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

4.7. volatile

๋ฉ€ํ‹ฐ ์ฝ”์–ด ํ”„๋กœ์„ธ์„œ์—์„œ๋Š” ์ฝ”์–ด๋งˆ๋‹ค ๋ณ„๋„์˜ ์บ์‹œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.
์ฝ”์–ด๋Š” ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์ฝ์–ด์˜จ ๊ฐ’์„ ์บ์‹œ์— ์ €์žฅํ•˜๊ณ  ์บ์‹œ์—์„œ ๊ฐ’์„ ์ฝ์–ด์„œ ์ž‘์—…ํ•œ๋‹ค.
๋‹ค์‹œ ๊ฐ™์€ ๊ฐ’์„ ์ฝ์–ด์˜ฌ ๋•Œ๋Š” ๋จผ์ € ์บ์‹œ์— ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ  ์—†์„ ๋•Œ๋งŒ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์ฝ์–ด์˜จ๋‹ค. ๋•Œ๋ฌธ์— ๋„์ค‘์— ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅ๋œ ๋ณ€์ˆ˜์˜ ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜์—ˆ๋Š”๋ฐ๋„ ์บ์‹œ์— ์ €์žฅ๋œ ๊ฐ’์ด ๊ฐฑ์‹ ๋˜์ง€ ์•Š์•„์„œ ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅ๋œ ๊ฐ’์ด ๋‹ค๋ฅธ ๊ฒฝ์šฐ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

๋ณ€์ˆ˜ ์•ž์— volatile์„ ๋ถ™์ด๋ฉด, ์ฝ”์–ด๊ฐ€ ๋ณ€์ˆ˜์˜ ๊ฐ’์„ ์ฝ์–ด์˜ฌ ๋•Œ ์บ์‹œ๊ฐ€ ์•„๋‹Œ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์ฝ์–ด์˜ค๊ธฐ ๋•Œ๋ฌธ์— ์บ์‹œ์™€ ๋ฉ”๋ชจ๋ฆฌ๊ฐ„์˜ ๊ฐ’์˜ ๋ถˆ์ผ์น˜๊ฐ€ ํ•ด๊ฒฐ๋œ๋‹ค.
๋ณ€์ˆ˜์— volatile์„ ๋ถ™์ด๋Š” ๋Œ€์‹ ์— synchronized๋ธ”๋Ÿญ์„ ์‚ฌ์šฉํ•ด๋„ ๊ฐ™์€ ํšจ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.
์“ฐ๋ ˆ๋“œ๊ฐ€ synchronized๋ธ”๋Ÿญ์œผ๋กœ ๋“ค์–ด๊ฐˆ ๋•Œ์™€ ๋‚˜์˜ฌ ๋•Œ, ์บ์‹œ์™€ ๋ฉ”๋ชจ๋ฆฌ๊ฐ„์˜ ๋™๊ธฐํ™”๊ฐ€ ์ด๋ฃจ์–ด์ ธ์„œ ๊ฐ’์˜ ๋ถˆ์ผ์น˜๊ฐ€ ํ•ด์†Œ๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

JVM์€ ๋ฐ์ดํ„ฐ๋ฅผ 4 byte(=32bit) ๋‹จ์œ„๋กœ ์ฒ˜๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์—, int์™€ int๋ณด๋‹ค ์ž‘์€ ํƒ€์ž…๋“ค์€ ํ•œ ๋ฒˆ์— ์ฝ๊ฑฐ๋‚˜ ์“ฐ๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ์ฆ‰, ๋‹จ ํ•˜๋‚˜์˜ ๋ช…๋ น์–ด๋กœ ์ฝ๊ฑฐ๋‚˜ ์“ฐ๊ธฐ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.
์ด๋Š” ๋” ์ด์ƒ ๋‚˜๋ˆŒ ์ˆ˜ ์—†๋Š” ์ตœ์†Œ์˜ ์ž‘์—…๋‹จ์œ„์ด๋ฏ€๋กœ, ์ž‘์—…์˜ ์ค‘๊ฐ„์— ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋ผ์–ด๋“ค ํ‹ˆ์ด ์—†๋‹ค.

ํ•˜์ง€๋งŒ ํฌ๊ธฐ๊ฐ€ 8byte์ธ long๊ณผ double ํƒ€์ž…์˜ ๋ณ€์ˆ˜๋Š” ํ•˜๋‚˜์˜ ๋ช…๋ น์–ด๋กœ ๊ฐ’์„ ์ฝ๊ฑฐ๋‚˜ ์“ธ ์ˆ˜ ์—†๋‹ค. ๋•Œ๋ฌธ์— ๋ณ€์ˆ˜์˜ ๊ฐ’์„ ์ฝ๋Š” ๊ณผ์ •์—์„œ ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋ผ์–ด๋“ค ์—ฌ์ง€๊ฐ€ ์žˆ๋‹ค.
์ด๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ๋ณ€์ˆ˜๋ฅผ ์ฝ๊ณ  ์“ฐ๋Š” ๋ชจ๋“  ๋ฌธ์žฅ์„ synchronized๋ธ”๋Ÿญ์œผ๋กœ ๊ฐ์‹ธ๊ฑฐ๋‚˜
๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•  ๋•Œ volatile์„ ๋ถ™์ด๋Š” ๊ฒƒ์ด๋‹ค.

์ƒ์ˆ˜์—๋Š” volatile์„ ๋ถ™์ผ ์ˆ˜ ์—†๋‹ค. ์ฆ‰, ๋ณ€์ˆ˜์— final๊ณผ volatile์„ ๊ฐ™์ด ๋ถ™์ผ ์ˆ˜ ์—†๋‹ค.
์ƒ์ˆ˜๋Š” ๋ณ€ํ•˜์ง€ ์•Š๋Š” ๊ฐ’์ด๋ฏ€๋กœ ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋“œ์— ์•ˆ์ „(thread-safe)ํ•˜๋‹ค.

Synchronized๋ธ”๋Ÿญ์€ ์—ฌ๋Ÿฌ ๋ฌธ์žฅ์„ ์›์žํ™”ํ•จ์œผ๋กœ์จ ์“ฐ๋ ˆ๋“œ์˜ ๋™๊ธฐํ™”๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
ํ•˜์ง€๋งŒ volatile์€ ๋ณ€์ˆ˜์˜ ์ฝ๊ฑฐ๋‚˜ ์“ฐ๊ธฐ๋ฅผ ์›์žํ™” ํ•  ๋ฟ, ๋™๊ธฐํ™”ํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค.
๊ทธ๋Ÿฌ๋ฏ€๋กœ ๋™๊ธฐํ™”๊ฐ€ ํ•„์š”ํ•  ๋•Œ, synchronized๋ธ”๋Ÿญ ๋Œ€์‹  volatile์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค.

4.8. fork & join ํ”„๋ ˆ์ž„์›Œํฌ

JDK1.7๋ถ€ํ„ฐ fork & join ํ”„๋ ˆ์ž„์›ค์ด ์ถ”๊ฐ€๋˜์–ด ํ•˜๋‚˜์˜ ์ž‘์—…์„ ์ž‘์€ ๋‹จ์œ„๋กœ ๋‚˜๋ˆ ์„œ ์—ฌ๋Ÿฌ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ์‰ฝ๊ฒŒ ๋งŒ๋“ค์–ด ์ค€๋‹ค.

RecursiveAction ๋ฐ˜ํ™˜๊ฐ’์ด ์—†๋Š” ์ž‘์—…์„ ๊ตฌํ˜„ํ•  ๋•Œ ์‚ฌ์šฉ
RecursiveTask ๋ฐ˜ํ™˜๊ฐ’์ด ์žˆ๋Š” ์ž‘์—…์„ ๊ตฌํ˜„ํ•  ๋•Œ ์‚ฌ์šฉ

๋‘ ํด๋ž˜์Šค ๋ชจ๋‘ compute()๋ผ๋Š” ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์„œ, ์ƒ์†์„ ํ†ตํ•ด ์ด ์ถ”์ƒ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค.

์“ฐ๋ ˆ๋“œ๋ฅผ ์‹œ์ž‘ํ•  ๋•Œ run()์ด ์•„๋‹ˆ๋ผ start()๋กœ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ,
fork & join ํ”„๋ ˆ์ž„์›Œํฌ๋กœ ์ˆ˜ํ–‰ํ•  ์ž‘์—…๋„ compute()๊ฐ€ ์•„๋‹Œ invoke()๋กœ ์‹œ์ž‘ํ•œ๋‹ค.

ForkJoinPool pool = new ForkJoinPool(); //์“ฐ๋ ˆ๋“œ ํ’€ ์ƒ์„ฑ
SumTask task = new SumTask(from, to); // ์ˆ˜ํ–‰ํ•  ์ž‘์—… ์ƒ์„ฑ

Long result = pool.invoke(task);  // invoke()๋ฅผ ํ˜ธ์ถœํ•ด์„œ ์ž‘์—…์„ ์‹œ์ž‘

ForkJoinPool์€ fork & joinํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ์ œ๊ณตํ•˜๋Š” thread pool๋กœ,
์ง€์ •๋œ ์ˆ˜์˜ ์“ฐ๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•ด์„œ ๋ฏธ๋ฆฌ ๋งŒ๋“ค์–ด ๋†“๊ณ  ๋ฐ˜๋ณตํ•ด์„œ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค.
์“ฐ๋ ˆ๋“œ ํ’€์€ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ˆ˜ํ–‰ํ•ด์•ผํ•˜๋Š” ์ž‘์—…์ด ๋‹ด๊ธด ํ๋ฅผ ์ œ๊ณตํ•˜๋ฉฐ,
๊ฐ ์“ฐ๋ ˆ๋“œ๋Š” ์ž์‹ ์˜ ์ž‘์—… ํ์— ๋‹ด๊ธด ์ž‘์—…์„ ์ˆœ์„œ๋Œ€๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค.
์“ฐ๋ ˆ๋“œ ํ’€์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ฝ”์–ด์˜ ๊ฐœ์ˆ˜๊ฐ€ ๋™์ผํ•œ ๊ฐœ์ˆ˜์˜ ์“ฐ๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

fork()๋Š” ์ž‘์—…์„ ์“ฐ๋ ˆ๋“œ์˜ ์ž‘์—… ํ์— ๋„ฃ๋Š” ๊ฒƒ์ด๊ณ , ์ž‘์—… ํ์— ๋“ค์–ด๊ฐ„ ์ž‘์—…์€ ๋” ์ด์ƒ ๋‚˜๋ˆŒ ์ˆ˜ ์—†์„ ๋•Œ๊นŒ์ง€ ๋‚˜๋‰œ๋‹ค.
์ฆ‰, compute()๋กœ ๋‚˜๋ˆ„๊ณ  fork()๋กœ ์ž‘์—… ํ์— ๋„ฃ๋Š” ์ž‘์—…์ด ๊ณ„์† ๋ฐ˜๋ณต๋œ๋‹ค.
๋‚˜๋ˆ ์ง„ ์ž‘์—…์€ ๊ฐ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๊ณจ๊ณ ๋ฃจ ๋‚˜๋ˆ ์„œ ์ฒ˜๋ฆฌํ•˜๊ณ 
์ž‘์—…์˜ ๊ฒฐ๊ณผ๋Š” join()์„ ํ˜ธ์ถœํ•ด์„œ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.

fork()์™€ join()์˜ ์ฐจ์ด

fork() - ํ•ด๋‹น ์ž‘์—…์„ ์“ฐ๋ ˆ๋“œ ํ’€์˜ ์ž‘์—… ํ์— ๋„ฃ๋Š”๋‹ค. ๋น„๋™๊ธฐ ๋ฉ”์„œ๋“œ
join() - ํ•ด๋‹น ์ž‘์—…์˜ ์ˆ˜ํ–‰์ด ๋๋‚  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ ธ๋‹ค๊ฐ€, ์ˆ˜ํ–‰์ด ๋๋‚˜๋ฉด ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ๋™๊ธฐ ๋ฉ”์„œ๋“œ

๋น„๋™๊ธฐ ๋ฉ”์„œ๋“œ๋Š” ์ผ๋ฐ˜ ๋ฉ”์„œ๋“œ์™€ ๋‹ฌ๋ฆฌ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœ๋งŒ ํ•  ๋ฟ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๋Š”๋‹ค.

public Long compute() {
  ...
  SumTask leftSum = new SumTask(from, half);
  SumTask rightSum = new SumTask(half+1, to);
  leftSum.fork(); // ๋น„๋™๊ธฐ ๋ฉ”์„œ๋“œ. ํ˜ธ์ถœ ํ›„ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๋Š”๋‹ค.
  
  return rightSum.compute()+leftSum.join(); // ๋™๊ธฐ๋ฉ”์„œ๋“œ. ํ˜ธ์ถœ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.
}