1212 ~ 0101


# 1212 ~ 0101

# 1213 - ๋žŒ๋‹ค ์บก์ฒ˜๋ง(Capturing Lambda)

๊ธฐ๋ณธ์ ์œผ๋กœ ๋žŒ๋‹ค ํ‘œํ˜„์‹์€ (ํŒŒ๋ผ๋ฏธํ„ฐ) -> ๋™์ž‘๊ณผ ๊ฐ™์€ ๊ตฌ์กฐ๋ฅผ ์ง€๋‹ˆ๋ฉฐ, ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋„˜๊ฒจ์ง„ ๋ณ€์ˆ˜๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋ฐ”๋””์—์„œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค. ๋žŒ๋‹ค ์บก์ฒ˜๋ง(capturing lambda)์ด๋ž€ ๊ฐ„๋‹จํžˆ ๋งํ•ด ์ด์ฒ˜๋Ÿผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋„˜๊ฒจ๋ฐ›์€ ๋ฐ์ดํ„ฐ๊ฐ€ ์•„๋‹Œ "๋žŒ๋‹ค์‹ ์™ธ๋ถ€์—์„œ ์ •์˜๋œ ๋ณ€์ˆ˜"๋ฅผ ์ฐธ์กฐํ•˜๋Š” ๋ณ€์ˆ˜๋ฅผ ๋žŒ๋‹ค์‹ ๋‚ด๋ถ€์— ์ €์žฅํ•˜๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๋™์ž‘์„ ์˜๋ฏธํ•œ๋‹ค. ์•„๋ž˜๋Š” ๊ทธ ์˜ˆ์ด๋‹ค.

void lambdaCapturing() {
   int localVariable = 1000;

   Runnable r = () -> System.out.println(localVariable);
}
1
2
3
4
5

# [ ์ œ์•ฝ ์กฐ๊ฑด: ์ง€์—ญ๋ณ€์ˆ˜๋Š” final์ด์–ด์•ผ ํ•œ๋‹ค ]

๋žŒ๋‹ค๋Š” ๊ฐ’์ด ๋‹จ ํ•œ ๋ฒˆ๋งŒ ํ• ๋‹น๋˜๋Š” ์ง€์—ญ๋ณ€์ˆ˜๋งŒ์„ ์บก์ฒ˜ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋งŒ์ผ ๋žŒ๋‹ค์—์„œ ์บก์ฒ˜๋˜๋Š” ์ง€์—ญ๋ณ€์ˆ˜์˜ ๊ฐ’์„ ์žฌํ• ๋‹น๋˜๋Š” ๊ฒฝ์šฐ ์ปดํŒŒ์ผ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ์ฆ‰, ๋ช…์‹œ์ ์œผ๋กœ final๋กœ ์„ ์–ธ๋˜์—ˆ๊ฑฐ๋‚˜, ์‹ค์งˆ์ ์œผ๋กœ final์ธ ์ง€์—ญ๋ณ€์ˆ˜๋งŒ ๋žŒ๋‹ค์‹ ๋ฐ”๋””์— ๋“ค์–ด์˜ฌ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

์ด๋Ÿฌํ•œ ์ œ์•ฝ์กฐ๊ฑด์€ JVM ๋ฉ”๋ชจ๋ฆฌ ๊ตฌ์กฐ์™€ ๊ด€๋ จ์ด ์žˆ๋‹ค. JVM ๋ฉ”๋ชจ๋ฆฌ์ƒ์œผ๋กœ ํž™์— ์ €์žฅ๋˜๋Š” ์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜ ๋“ฑ๊ณผ๋Š” ๋‹ฌ๋ฆฌ, ์ง€์—ญ๋ณ€์ˆ˜๋Š” ์Šคํƒ์— ์ €์žฅ๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด '์ง€์—ญ๋ณ€์ˆ˜์˜ ๊ฐ’์„ ์บก์ฒ˜ํ•˜๋Š” ๋žŒ๋‹ค'๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ํ•œ ๋ฒˆ ์ƒ๊ฐํ•ด๋ณด์ž. ํ•ด๋‹น ๋ฉ”์„œ๋“œ์˜ ์‹คํ–‰์ด ์ข…๋ฃŒ๋˜๋Š” ๊ฒฝ์šฐ, JVM์€ ๋ฐ˜ํ™˜๋˜๋Š” ๋žŒ๋‹ค์‹์˜ ๋ฐ”๋””์— ํฌํ•จ๋˜์–ด ์žˆ๋Š” ์ง€์—ญ๋ณ€์ˆ˜์˜ ํ• ๋‹น์„ ํ•ด์ œํ•œ๋‹ค. ๊ทธ๋Ÿผ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ๋žŒ๋‹ค๋Š” ์ง€์—ญ๋ณ€์ˆ˜์˜ ๊ฐ’์„ ์•„๋ฌด ๋ฌธ์ œ ์—†์ด ์ฐธ์กฐํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋Š” ๋žŒ๋‹ค ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉ๋˜๋Š” ์ง€์—ญ๋ณ€์ˆ˜๋Š” ์›๋ณธ ์ง€์—ญ๋ณ€์ˆ˜๋ฅผ ๋ณต์ œํ•œ ๋ฐ์ดํ„ฐ์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์ œ ์ง€์—ญ๋ณ€์ˆ˜์˜ ํ• ๋‹น์ด ํ•ด์ œ๋˜์–ด๋„ ๋žŒ๋‹ค ๋‚ด๋ถ€์˜ ๊ฐ’์€ ์œ ์ง€๋˜๋Š” ๊ฒƒ์ด๋ฉฐ, ๋ณต์ œํ’ˆ์˜ ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•„์•ผ ํ•œ๋‹ค๋Š” ์ด์œ ๋กœ ๋‹จ ํ•œ ๋ฒˆ๋งŒ ๊ฐ’์„ ํ• ๋‹นํ•ด์•ผ ํ•œ๋‹ค๋Š” ์ œ์•ฝ์ด ์ƒ๊ฒจ๋‚œ ๊ฒƒ์ด๋‹ค.

void useLambda() {
   Supplier<Integer> lambda = getLambda();

   int actual = lambda.get();

   System.out.println(actual); // 1005
}

// ์ง€์—ญ๋ณ€์ˆ˜๋ฅผ ์บก์ฒ˜ํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋Š” ๋žŒ๋‹ค๋ฅผ ์™ธ๋ถ€๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์„œ๋“œ
private Supplier<Integer> getLambda() {
   int localVariable = 1000; // ์ง€์—ญ๋ณ€์ˆ˜ localVariable

   return () -> localVariable + 5; // ์ž์œ ๋ณ€์ˆ˜ localVariable
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

๊ทธ๋ฆฌ๊ณ  ์ด์ฒ˜๋Ÿผ ๋žŒ๋‹ค์‹ ๋‚ด๋ถ€์—์„œ ์ €์žฅ๋˜๋Š” ์ง€์—ญ๋ณ€์ˆ˜์˜ ๋ณต์ œํ’ˆ์€ ์›๋ณธ์ด ๋˜๋Š” ์ง€์—ญ๋ณ€์ˆ˜์ด ์‚ฌ๋ผ์ ธ๋„ ์ž์œ ๋กญ๊ฒŒ ์กด์žฌํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ž์œ ๋ณ€์ˆ˜๋ผ๊ณ  ๋ถˆ๋ฆฐ๋‹ค.

์‚ฌ์‹ค ์ง€์—ญ๋ณ€์ˆ˜์˜ ๋ถˆ๋ณ€์„ฑ์„ ๊ฐ•์ œํ•˜๋Š” ๊ฒƒ์€ ๋”ฑํžˆ ๋ฌธ์ œ๋ผ๊ณ  ๋ณด๊ธฐ ์–ด๋ ต๋‹ค. ๋ถˆ๋ณ€์„ฑ์ด ์ง€๋‹Œ ๋‹ค์–‘ํ•œ ์ด์ ๋„ ์žˆ๊ฒ ์ง€๋งŒ, ์™ธ๋ถ€ ๋ณ€์ˆ˜์˜ ๊ฐ’์„ ์ง์ ‘์ ์œผ๋กœ ๋ณ€ํ™”ํ•˜๋Š” ์ผ๋ฐ˜์ ์ธ ์ ˆ์ฐจํ˜•/๋ช…๋ นํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ ํŒจํ„ด์„ ์˜ˆ๋ฐฉํ•œ๋‹ค๋Š” ์ ์ด ๊ฐ€์žฅ ํฐ ์ด์ ์ด๋ผ๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค์ ์„ ์ œ์•ฝ ์กฐ๊ฑด์˜ ์ด์ ์œผ๋กœ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.


# 1215 - Thread์™€ Runnable

# 1. Thread์™€ Runnable์— ๋Œ€ํ•œ ์ดํ•ด ๋ฐ ์‚ฌ์šฉ๋ฒ•

# [ ์“ฐ๋ ˆ๋“œ์™€ ์ž๋ฐ”์˜ ๋ฉ€ํ‹ฐ ์“ฐ๋ ˆ๋“œ ]

์“ฐ๋ ˆ๋“œ๋ž€ ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰์˜ ๊ฐ€์žฅ ์ž‘์€ ๋‹จ์œ„์ด๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ์ž๋ฐ” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“ค์–ด ์‹คํ–‰ํ•˜๋ฉด 1๊ฐœ์˜ ๋ฉ”์ธ(main) ์“ฐ๋ ˆ๋“œ์— ์˜ํ•ด ํ”„๋กœ๊ทธ๋žจ์ด ์‹คํ–‰๋œ๋‹ค. ํ•˜์ง€๋งŒ 1๊ฐœ์˜ ์“ฐ๋ ˆ๋“œ ๋งŒ์œผ๋กœ๋Š” ๋™์‹œ์— ์—ฌ๋Ÿฌ ์ž‘์—…์„ ํ•  ์ˆ˜ ์—†๋‹ค. ๋™์‹œ์— ์—ฌ๋Ÿฌ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด, ๋ณ„๋„์˜ ์“ฐ๋ ˆ๋“œ๋ฅผ ๋งŒ๋“ค์–ด ์‹คํ–‰์‹œ์ผœ์ค˜์•ผ ํ•˜๋Š”๋ฐ, ์ž๋ฐ”๋Š” ๋ฉ€ํ‹ฐ ์“ฐ๋ ˆ๋“œ ๊ธฐ๋ฐ˜์œผ๋กœ ๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์ง€์›ํ•˜๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ•๋“ค์„ ๊ณ„์†ํ•ด์„œ ๋ฐœ์ „์‹œ์ผœ ์™”๋‹ค.
๊ทธ ์ค‘์—์„œ Thread์™€ Runnable์€ ์ž๋ฐ” ์ดˆ๊ธฐ๋ถ€ํ„ฐ ๋ฉ€ํ‹ฐ ์“ฐ๋ ˆ๋“œ๋ฅผ ์œ„ํ•ด ์ œ๊ณต๋˜์—ˆ๋˜ ๊ธฐ์ˆ ์ด๋‹ค.

  • java5 ์ด์ „ : Runnable๊ณผ Thread
  • java5 : Callable๊ณผ Future ๋ฐ Executor, ExecutorService, Executors
  • java7 : Fork/Join ๋ฐ RecursiveTask
  • java9 : Flow

# [ Thread ํด๋ž˜์Šค ]

Thread๋Š” ์“ฐ๋ ˆ๋“œ ์ƒ์„ฑ์„ ์œ„ํ•ด Java์—์„œ ๋ฏธ๋ฆฌ ๊ตฌํ˜„ํ•ด๋‘” ํด๋ž˜์Šค์ด๋‹ค. Thread๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฉ”์†Œ๋“œ๋“ค์„ ์ œ๊ณตํ•œ๋‹ค.

  • sleep
    • ํ˜„์žฌ ์“ฐ๋ ˆ๋“œ ๋ฉˆ์ถ”๊ธฐ
    • ์ž์›์„ ๋†“์•„์ฃผ์ง€๋Š” ์•Š๊ณ , ์ œ์–ด๊ถŒ์„ ๋„˜๊ฒจ์ฃผ๋ฏ€๋กœ ๋ฐ๋“œ๋ฝ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Œ
  • interupt
    • ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๋ฅผ ๊นจ์›Œ์„œ interruptedException์„ ๋ฐœ์ƒ์‹œํ‚ด
    • Interupt๊ฐ€ ๋ฐœ์ƒํ•œ ์“ฐ๋ ˆ๋“œ๋Š” ์˜ˆ์™ธ๋ฅผ catchํ•˜์—ฌ ๋‹ค๋ฅธ ์ž‘์—…์„ ํ•  ์ˆ˜ ์žˆ์Œ
  • join
    • ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ์˜ ์ž‘์—…์ด ๋๋‚  ๋•Œ ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๊ฒŒ ํ•จ
    • ์“ฐ๋ ˆ๋“œ์˜ ์ˆœ์„œ๋ฅผ ์ œ์–ดํ•  ๋•Œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ

Thread ํด๋ž˜์Šค๋กœ ์“ฐ๋ ˆ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๋ ค๋ฉด ์ด๋ฅผ ์ƒ์†๋ฐ›๋Š” ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๊ณ , ๋‚ด๋ถ€์—์„œ run ๋ฉ”์†Œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  Thread์˜ start ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด run ๋ฉ”์†Œ๋“œ๊ฐ€ ์‹คํ–‰๋œ๋‹ค. ์‹คํ–‰ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด main ์“ฐ๋ ˆ๋“œ๊ฐ€ ์•„๋‹Œ ๋ณ„๋„์˜ ์“ฐ๋ ˆ๋“œ์—์„œ ์‹คํ–‰๋จ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

@Test
void threadStart() {
    Thread thread = new MyThread();

    thread.start();
    System.out.println("Hello: " + Thread.currentThread().getName());
}

static class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("Thread: " + Thread.currentThread().getName());
    }
}

// ์ถœ๋ ฅ ๊ฒฐ๊ณผ
// Hello: main
// Thread: Thread-2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

์—ฌ๊ธฐ์„œ run์„ ์ง์ ‘ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ start๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์— ์ฃผ์˜ํ•ด์•ผ ํ•œ๋‹ค. ์šฐ๋ฆฌ๋Š” ํ•ด๋‹น ๋ฉ”์†Œ๋“œ์˜ ์‹คํ–‰์„ ๋ณ„๋„์˜ ์“ฐ๋ ˆ๋“œ๋กœ ํ•˜๊ณ  ์‹ถ์€ ๊ฒƒ์ธ๋ฐ, run์„ ์ง์ ‘ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์€ ๋ฉ”์ธ ์“ฐ๋ ˆ๋“œ์—์„œ ๊ฐ์ฒด์˜ ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์— ๋ถˆ๊ณผํ•˜๋‹ค. ์ด๋ฅผ ๋ณ„๋„์˜ ์“ฐ๋ ˆ๋“œ๋กœ ์‹คํ–‰์‹œํ‚ค๋ ค๋ฉด JVM์˜ ๋„์›€์ด ํ•„์š”ํ•˜๋‹ค. ๋”ฐ๋ผ์„œ start๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

public synchronized void start() {
    if (threadStatus != 0)
        throw new IllegalThreadStateException();

    group.add(this);

    boolean started = false;
    try {
        start0();
        started = true;
    } finally {
        try {
            if (!started) {
                group.threadStartFailed(this);
            }
        } catch (Throwable ignore) {
        
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

์œ„์˜ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด ์•Œ ์ˆ˜ ์žˆ๋“ฏ์ด start๋Š” ํฌ๊ฒŒ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ณผ์ •์œผ๋กœ ์ง„ํ–‰๋œ๋‹ค.

  1. ์“ฐ๋ ˆ๋“œ๊ฐ€ ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ์ง€ ๊ฒ€์‚ฌํ•จ

์“ฐ๋ ˆ๋“œ๋Š” New, Runnable, Waiting, Timed Waiting, Terminated ์ด 5๊ฐ€์ง€ ์ƒํƒœ๊ฐ€ ์žˆ๋‹ค. start ๊ฐ€์žฅ ์ฒ˜์Œ์—๋Š” ํ•ด๋‹น ์“ฐ๋ ˆ๋“œ๊ฐ€ ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ์ธ์ง€(0์ธ์ง€) ํ™•์ธํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋งŒ์•ฝ ์“ฐ๋ ˆ๋“œ๊ฐ€ New(0) ์ƒํƒœ๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด IllegalThreadStateException ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค. image

  1. ์“ฐ๋ ˆ๋“œ๋ฅผ ์“ฐ๋ ˆ๋“œ ๊ทธ๋ฃน์— ์ถ”๊ฐ€ํ•จ

๊ทธ ๋‹ค์Œ ์“ฐ๋ ˆ๋“œ ๊ทธ๋ฃน์— ํ•ด๋‹น ์“ฐ๋ ˆ๋“œ๋ฅผ ์ถ”๊ฐ€์‹œํ‚จ๋‹ค. ์—ฌ๊ธฐ์„œ ์“ฐ๋ ˆ๋“œ ๊ทธ๋ฃน์ด๋ž€ ์„œ๋กœ ๊ด€๋ จ์žˆ๋Š” ์“ฐ๋ ˆ๋“œ๋ฅผ ํ•˜๋‚˜์˜ ๊ทธ๋ฃน์œผ๋กœ ๋ฌถ์–ด ๋‹ค๋ฃจ๊ธฐ ์œ„ํ•œ ์žฅ์น˜์ธ๋ฐ, ์ž๋ฐ”์—์„œ๋Š” ThreadGroup ํด๋ž˜์Šค๋ฅผ ์ œ๊ณตํ•œ๋‹ค. ์“ฐ๋ ˆ๋“œ ๊ทธ๋ฃน์— ํ•ด๋‹น ์“ฐ๋ ˆ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ์“ฐ๋ ˆ๋“œ ๊ทธ๋ฃน์— ์‹คํ–‰ ์ค€๋น„๋œ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์žˆ์Œ์„ ์•Œ๋ ค์ฃผ๊ณ , ๊ด€๋ จ ์ž‘์—…๋“ค์ด ๋‚ด๋ถ€์ ์œผ๋กœ ์ง„ํ–‰๋œ๋‹ค.

  1. ์“ฐ๋ ˆ๋“œ๋ฅผ JVM์ด ์‹คํ–‰์‹œํ‚ด

๊ทธ๋ฆฌ๊ณ  start0 ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š”๋ฐ, ์ด๊ฒƒ์€ native ๋ฉ”์†Œ๋“œ๋กœ ์„ ์–ธ๋˜์–ด ์žˆ๋‹ค. ์ด๊ฒƒ์€ JVM์— ์˜ํ•ด ํ˜ธ์ถœ๋˜๋Š”๋ฐ, ์ด๊ฒƒ์ด ๋‚ด๋ถ€์ ์œผ๋กœ run์„ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ๋„๋ฆฌ๊ณ  ์“ฐ๋ ˆ๋“œ์˜ ์ƒํƒœ ์—ญ์‹œ Runnable๋กœ ๋ฐ”๋€Œ๊ฒŒ ๋œ๋‹ค. ๊ทธ๋ž˜์„œ start๋Š” ์—ฌ๋Ÿฌ ๋ฒˆ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๊ณ  1๋ฒˆ๋งŒ ๊ฐ€๋Šฅํ•˜๋‹ค.

private native void start0();
1

# [ Runnable ์ธํ„ฐํŽ˜์ด์Šค ]

Runnable ์ธํ„ฐํŽ˜์ด์Šค๋Š” 1๊ฐœ์˜ ๋ฉ”์†Œ๋“œ ๋งŒ์„ ๊ฐ–๋Š” ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค์ด๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ๋žŒ๋‹ค๋กœ๋„ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค.

@FunctionalInterface
public interface Runnable {

    public abstract void run();
    
}
1
2
3
4
5
6

์ด๊ฒƒ์€ ์“ฐ๋ ˆ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•œ ํ…œํ”Œ๋ฆฟ์— ํ•ด๋‹นํ•˜๋Š”๋ฐ, ํ•ด๋‹น ์ธํ„ฐํŽ˜์ด์Šค์˜ ๊ตฌํ˜„์ฒด๋ฅผ ๋งŒ๋“ค๊ณ  Thread ๊ฐ์ฒด ์ƒ์„ฑ ์‹œ์— ๋„˜๊ฒจ์ฃผ๋ฉด ์‹คํ–‰ ๊ฐ€๋Šฅํ•˜๋‹ค. ์•ž์„œ ์‚ดํŽด๋ณธ Thread ํด๋ž˜์Šค๋Š” ๋ฐ˜๋“œ์‹œ run ๋ฉ”์†Œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ–ˆ๋Š”๋ฐ, Thread ํด๋ž˜์Šค๊ฐ€ Runnable๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

public class Thread implements Runnable {
    ...
}
1
2
3

๊ธฐ์กด์— Thread๋กœ ์ž‘์„ฑ๋˜์—ˆ๋˜ ์ฝ”๋“œ๋ฅผ Runnable๋กœ ๋ณ€๊ฒฝํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค. ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋ณ„๋„์˜ ์“ฐ๋ ˆ๋“œ์—์„œ ์‹คํ–‰๋จ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

@Test
void runnable() {
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            System.out.println("Thread: " + Thread.currentThread().getName());
        }
    };

    Thread thread = new Thread(runnable);
    thread.start();
    System.out.println("Hello: " + Thread.currentThread().getName());
}

// ์ถœ๋ ฅ ๊ฒฐ๊ณผ
// Hello: main
// Thread: Thread-1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 2. Thread์™€ Runnable ๋น„๊ต

# [ Threaddhk Runnable ๋น„๊ต ]

Runnable์€ ์ต๋ช… ๊ฐ์ฒด ๋ฐ ๋žŒ๋‹ค๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, Thread๋Š” ๋ณ„๋„์˜ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค๋Š” ์ ์—์„œ ๋ฒˆ๊ฑฐ๋กญ๋‹ค. ๋˜ํ•œ Java์—์„œ๋Š” ๋‹ค์ค‘์ƒ์†์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋ฏ€๋กœ Thread ํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›์œผ๋ฉด ๋‹ค๋ฅธ ํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›์„ ์ˆ˜ ์—†์–ด์„œ ์ข‹์ง€ ์•Š๋‹ค. ๋˜ํ•œ Thread ํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›์œผ๋ฉด ํ•ด๋‹น ํด๋ž˜์Šค์— ๊ตฌํ˜„๋œ ์ฝ”๋“œ๋“ค์— ์˜ํ•ด ๋” ๋งŽ์€ ์ž์›์„ ํ•„์š”๋กœ ํ•˜๋ฏ€๋กœ Runnable์ด ์ฃผ๋กœ ์‚ฌ์šฉ๋œ๋‹ค.
๋ฌผ๋ก  Thread ๊ด€๋ จ ๊ธฐ๋Šฅ์˜ ํ™•์žฅ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋Š” Thread ํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›์•„ ๊ตฌํ˜„ํ•ด์•ผ ํ•  ๋•Œ๋„ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ๊ฑฐ์˜ ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ์—๋Š” Runnable ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ•ด๊ฒฐ ๊ฐ€๋Šฅํ•˜๋‹ค.

# [ Thread์™€ Runnable์˜ ๋‹จ์  ๋ฐ ํ•œ๊ณ„ ]

  • ์ง€๋‚˜์น˜๊ฒŒ ์ €์ˆ˜์ค€์˜ API(์“ฐ๋ ˆ๋“œ์˜ ์ƒ์„ฑ)์˜์กดํ•จ
  • ๊ฐ’์˜ ๋ฐ˜ํ™˜์ด ๋ถˆ๊ฐ€๋Šฅ
  • ๋งค๋ฒˆ ์“ฐ๋ ˆ๋“œ ์ƒ์„ฑ๊ณผ ์ข…๋ฃŒํ•˜๋Š” ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ๋ฐœ์ƒ
  • ์“ฐ๋ ˆ๋“œ๋“ค์˜ ๊ด€๋ฆฌ๊ฐ€ ์–ด๋ ค์›€

Executor, ExecutorService, ScheduledExecutionService์™€ Callable, Future


# 1224 - ์ž๋ฐ” 8 ํ‘œ์ค€ API์˜ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค

# ์ž๋ฐ” 8์ด ์ œ๊ณตํ•˜๋Š” ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค

์ž๋ฐ” 8๋ฒ„์ „๋ถ€ํ„ฐ ๋นˆ๋ฒˆํ•˜๊ฒŒ ์‚ฌ์šฉ๋˜๋Š” ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ java.util.function ํ‘œ์ค€ API ํŒจํ‚ค์ง€๋กœ ์ œ๊ณตํ•œ๋‹ค. ์ œ๊ณต๋˜๋Š” ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋Š” ํฌ๊ฒŒ 5๊ฐ€์ง€๋กœ Consumer, Supplier, Function, Operator, Predicate ์ด๋‹ค. ๊ฐ ์ธํ„ฐํŽ˜์ด์Šค๋Š” ๋˜ ์—ฌ๋Ÿฌ๊ฐœ์˜ ์–ธํ„ฐํŽ˜์ด์Šค๋กœ ๋‚˜๋‰œ๋‹ค.

๋‘๊ฐœ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๋ฐ›๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ผ๋ฉด Bi ๋ผ๋Š” ์ ‘๋‘์‚ฌ, ์ •์ˆ˜ ํƒ€์ž…์„ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ „๋‹ฌ๋ฐ›๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ผ๋ฉด Int ๋ผ๋Š” ์ ‘๋‘์‚ฌ๊ฐ€ ํ˜ป์€ ์‹ค์ˆ˜ ํƒ€์ž…์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ผ๋ฉด AsDouble ๊ณผ ๊ฐ™์€ ์ ‘๋ฏธ์‚ฌ๊ฐ€ ๋‹ฌ๋ ค์žˆ๋Š” ๋“ฑ ์ผ์ •ํ•œ ๋„ค์ด๋ฐ ๊ทœ์น™์ด ์กด์žฌํ•œ๋‹ค.

# Consumer ๊ณ„์—ด

๋งค๊ฐœ๊ฐ’์€ ์žˆ๊ณ  ๋ฐ˜ํ™˜๊ฐ’์€ ์—†๋‹ค. ๋งค๊ฐœ๊ฐ’์„ ์ „๋‹ฌ๋ฐ›์•„ ์‚ฌ์šฉํ•˜๊ณ  ์•„๋ฌด๊ฒƒ๋„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š์„ ๋•Œ ์‚ฌ์šฉ๋œ๋‹ค. ์ด๋ฅผ ์†Œ๋น„(Consume) ํ•œ๋‹ค๊ณ  ํ‘œํ˜„ํ•œ๋‹ค. accept ์ถ”์ƒ ๋ฉ”์†Œ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

# [ ์šฉ๋ก€ ]

๋Œ€ํ‘œ์ ์œผ๋กœ Stream ์˜ forEach ๋ฉ”์†Œ๋“œ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜ ํƒ€์ž…์ด Consumer ์ด๋‹ค

List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6);
numbers.stream().forEach(number -> System.out.println(number));
// Consumer ์ „๋‹ฌ๋จ
1
2
3

๋งค๊ฐœ๊ฐ’์œผ๋กœ number๋ฅผ ๋ฐ›๊ณ  ๋žŒ๋‹ค ํ‘œํ˜„์‹ ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉ๋˜๊ธฐ๋งŒ ํ•  ๋ฟ ์•„๋ฌด๊ฒƒ๋„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

๋˜ํ•œ Map ์˜ forEach ๋ฉ”์†Œ๋“œ๋Š” BiConsumer ํƒ€์ž…์„ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›๋Š”๋‹ค.

Map<String, Integer> map = Map.of("hudi", 25, "baby", 1);
map.forEach((name, number) -> System.out.println(name + "๋Š” " + number + "์‚ด"));
// BiConsumer ์ „๋‹ฌ๋จ
1
2
3

์œ„์™€ ๊ฐ™์ด ์ฒซ๋ฒˆ์งธ ๋งค๊ฐœ๋ณ€์ˆ˜๋Š” Map ์˜ key๋ฅผ, ๋‘๋ฒˆ์งธ ๋งค๊ฐœ๋ณ€์ˆ˜๋Š” Map ์˜ value ๋ฅผ ์ „๋‹ฌ๋ฐ›๋Š”๋‹ค.

# Supplier ๊ณ„์—ด

๋งค๊ฐœ๊ฐ’์€ ์—†๊ณ , ๋ฐ˜ํ™˜๊ฐ’์€ ์žˆ๋‹ค. ์‹คํ–‰ ํ›„ ํ˜ธ์ถœํ•œ ๊ณณ์œผ๋กœ ๋ฐ์ดํ„ฐ ๊ณต๊ธ‰(Supply) ํ•œ๋‹ค. getXXX ์ถ”์ƒ๋ฉ”์†Œ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

# [ ์šฉ๋ก€ ]

Stream์˜ generate๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ Supplierํƒ€์ž…์„ ๋ฐ›์•„ ํ•ด๋‹น get๋ฉ”์†Œ๋“œ์˜ ๋ฐ˜ํ™˜๊ฐ’์œผ๋กœ ๋ฌดํ•œํ•œ Stream ์„ ์ƒ์„ฑํ•œ๋‹ค.

Stream.generate(() -> "Infinite Stream!") // Supplier ์ „๋‹ฌ๋จ
        .limit(5)
        .forEach(System.out::println);
1
2
3

# Function ๊ณ„์—ด

๋งค๊ฐœ๊ฐ’๋„ ์žˆ๊ณ , ๋ฆฌํ„ด๊ฐ’๋„ ์žˆ๋‹ค. ์ฃผ๋กœ ๋งค๊ฐœ๊ฐ’์„ ๋ฐ˜ํ™˜๊ฐ’์œผ๋กœ ๋งคํ•‘ํ•  ๋•Œ ์ฆ‰, ํƒ€์ž… ๋ณ€ํ™˜์ด ๋ชฉ์ ์ผ ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค. applyXXX ์ถ”์ƒ ๋ฉ”์†Œ๋“œ๋ฅผ ๊ฐ–๊ณ  ์žˆ๋‹ค.

# [ ์šฉ๋ก€ ]

IntStream์˜ mapToObj๋Š” ์ •์ˆ˜๋ฅผ ๊ฐ์ฒด๋กœ ๋งคํ•‘ํ•˜๋Š” ๋ฉ”์†Œ๋“œ์ด๋‹ค. ์ด ๋ฉ”์†Œ๋“œ๋Š” ์ธ์ž๋กœ IntFunction ํƒ€์ž…์„ ์ „๋‹ฌ๋ฐ›๋Š”๋‹ค.

List<Number> numbers = IntStream.rangeClosed(0, 10)
        .mapToObj(number -> new Number(number)) // IntFunction ์ „๋‹ฌ๋จ
        .collect(Collectors.toList());
1
2
3

# Operator ๊ณ„์—ด

Function๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ, ๋งค๊ฐœ๊ฐ’๋„ ์žˆ๊ณ , ๋ฐ˜ํ™˜๊ฐ’๋„ ์žˆ๋‹ค. ์ฃผ๋กœ ๋งค๊ฐœ๊ฐ’์„ ์—ฐ์‚ฐ (Operation) ํ•˜์—ฌ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•  ๋•Œ ์‚ฌ์šฉ๋œ๋‹ค. Function๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ applyXXX ์ถ”์ƒ ๋ฉ”์†Œ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

# [ ์šฉ๋ก€ ]

Stream์˜ ์—ฌ๋Ÿฌ ์˜ค๋ฒ„๋กœ๋“œ๋œ reduce ๋ฉ”์†Œ๋“œ ์ค‘ ํ•˜๋‚˜๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ BinaryOperator๋ฅผ ์ „๋‹ฌ๋ฐ›๋Š”๋‹ค. ์•„๋ž˜๋Š” BinaryOperator๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์ปฌ๋ ‰์…˜์˜ ๋ชจ๋“  ์ˆ˜๋ฅผ ๋”ํ•˜๋Š” ์˜ˆ์‹œ์ด๋‹ค.

List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6);
Integer sum = numbers.stream()
        .reduce((acc, cur) -> acc + cur) // BinaryOperator ์ „๋‹ฌ๋จ
        .get();
1
2
3
4

# Predicate ๊ณ„์—ด

๋งค๊ฐœ๊ฐ’์€ ์žˆ๊ณ , ๋ฐ˜ํ™˜ ํƒ€์ž…์€ boolean ์ด๋‹ค. ๋งค๊ฐœ๊ฐ’์„ ๋ฐ›์•„ ๊ฒ€์‚ฌํ•˜๊ณ  true/false๋ฅผ ๋ฐ˜ํ™˜ํ• ๋•Œ ์‚ฌ์šฉ๋œ๋‹ค. test ์ถ”์ƒ ๋ฉ”์†Œ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

# [ ์šฉ๋ก€ ]

Stream์˜ allMatch ๋ฉ”์†Œ๋“œ๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ Predicate ํƒ€์ž…์„ ์ „๋‹ฌ๋ฐ›์•„, ์ปฌ๋ ‰์…˜์˜ ๋ชจ๋“  ์š”์†Œ๊ฐ€ ์ฃผ์–ด์ง„ ์กฐ๊ฑด์— ๋ชจ๋‘ ์ผ์น˜ํ•˜๋ฉด ture๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

List<Integer> numbers = List.of(10, 20, 25, 15, 30, 35);
boolean allMatched = numbers.stream()
        .allMatch(number -> number > 5);
1
2
3

Consumer, Function, Operator ๊ณ„์—ด์€ andThen๊ณผ copose๋ผ๋Š” ๋””ํดํŠธ ๋ฉ”์†Œ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. ๋˜ํ•œ Predicate ๊ณ„์—ด์€ and, or, negate ๋ผ๋Š” ๋””ํดํŠธ ๋ฉ”์†Œ๋“œ, ๊ทธ๋ฆฌ๊ณ  isEqual์ด๋ผ๋Š” ์ •์  ๋ฉ”์†Œ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

Last update: January 2, 2023 23:33
Contributors: jaesungahn91