๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Today I Learned(TIL)/์ŠคํŒŒ๋ฅดํƒ€ ๋‚ด์ผ๋ฐฐ์›€์บ ํ”„

ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ธฐ์ดˆ_Day 12

by carrot0911 2024. 11. 23.

์˜ค๋Š˜ ํ•œ ๊ณต๋ถ€๐Ÿง

์˜ค์ „

  • ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋ฌธ์ œ(SQL, Java) 1๋ฌธ์ œ ํ’€์ด & ๋ธ”๋กœ๊ทธ ์ •๋ฆฌ
  • Java ๋ฌธ๋ฒ• ์ข…ํ•ฉ๋ฐ˜ 5์ฃผ์ฐจ ๊ฐ•์˜ ๋ณต์Šต

์˜คํ›„

  • Java ๋ฌธ๋ฒ• ์ข…ํ•ฉ๋ฐ˜ 5์ฃผ์ฐจ ๊ฐ•์˜ ๋ณต์Šต
  • TIL ๋ธ”๋กœ๊ทธ ์ž‘์„ฑ

 

์˜ค๋Š˜ ์–ป์€ ๋‚ด์šฉ ์ •๋ฆฌโœ๏ธ

Java ๋ฌธ๋ฒ• ์ข…ํ•ฉ๋ฐ˜_5์ฃผ์ฐจ ๊ฐ•์˜ ๋‚ด์šฉ ์ •๋ฆฌ

Process์™€ Thread

Process : ์šด์˜์ฒด์ œ๋กœ๋ถ€ํ„ฐ ์ž์›์„ ํ• ๋‹น๋ฐ›๋Š” ์ž‘์—…์˜ ๋‹จ์œ„

  • ์‹คํ–‰ ์ค‘์ธ ํ”„๋กœ๊ทธ๋žจ์„ ์˜๋ฏธํ•œ๋‹ค.
  • OS๊ฐ€ ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰์„ ์œ„ํ•œ ํ”„๋กœ์„ธ์Šค๋ฅผ ํ• ๋‹นํ•ด์ค„ ๋•Œ ํ”„๋กœ์„ธ์Šค ์•ˆ์— ํ”„๋กœ๊ทธ๋žจ Code์™€ Data ๊ทธ๋ฆฌ๊ณ  ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ(Stack, Heap)์„ ํ•จ๊ป˜ ํ• ๋‹นํ•ด์ค€๋‹ค.
    • Code๋Š” Java main ๋ฉ”์„œ๋“œ์™€ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ๋งํ•œ๋‹ค.
    • Data๋Š” ํ”„๋กœ๊ทธ๋žจ์ด ์‹คํ–‰ ์ค‘ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋Š” ์ €์žฅ๊ณต๊ฐ„์„ ์˜๋ฏธํ•œ๋‹ค.
      • ์ „์—ญ๋ณ€์ˆ˜, ์ •์ ๋ณ€์ˆ˜(static), ๋ฐฐ์—ด ๋“ฑ ์ดˆ๊ธฐํ™”๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋Š” ๊ณต๊ฐ„
    • Memory(๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ) → ๋™์ ์œผ๋กœ ํ•„์š”ํ•œ ๋ณ€์ˆ˜ ์ €์žฅํ•˜๋Š” ๊ณต๊ฐ„
      • Stack : ์ง€์—ญ๋ณ€์ˆ˜, ๋งค๊ฐœ๋ณ€์ˆ˜ ๋ฆฌํ„ด ๋ณ€์ˆ˜ ์ €์žฅํ•˜๋Š” ๊ณต๊ฐ„
      • Heap : ํ”„๋กœ๊ทธ๋žจ์ด ๋™์ ์œผ๋กœ ํ•„์š”ํ•œ ๋ณ€์ˆ˜๋ฅผ ์ €์žฅํ•˜๋Š” ๊ณต๊ฐ„ (new( ), mallock( ))
  • ๊ฐ ํ”„๋กœ๊ทธ๋žจ์€ Process๋ฅผ ํ†ตํ•ด Code, Data, Memory(Stack, Heap)๋ฅผ OS๋กœ๋ถ€ํ„ฐ ํ• ๋‹น๋ฐ›๋Š”๋‹ค.

Thread : ํ”„๋กœ์„ธ์Šค๊ฐ€ ํ• ๋‹น๋ฐ›์€ ์ž์›์„ ์ด์šฉํ•˜๋Š”(๊ณต์œ ํ•˜๋Š”) ์‹คํ–‰์˜ ๋‹จ์œ„ → ์ž‘์—…์ž, ์ผ๊พผ

  • Process๊ฐ€ ์ž‘์—… ์ค‘์ธ ํ”„๋กœ๊ทธ๋žจ์—์„œ ์‹คํ–‰์š”์ฒญ์ด ๋“ค์–ด์˜ค๋ฉด Thread(์ผ๊พผ)์„ ๋งŒ๋“ค์–ด ์ฒ˜๋ฆฌํ•˜๋„๋ก ํ•œ๋‹ค.
  • Thread๋“ค์€ ์‹คํ–‰์„ ์œ„ํ•œ ํ”„๋กœ์„ธ์Šค ๋‚ด ์ฃผ์†Œ๊ณต๊ฐ„์ด๋‚˜ ๋ฉ”๋ชจ๋ฆฌ๊ณต๊ฐ„(Heap)์„ ๊ณต์œ ๋ฐ›๋Š”๋‹ค.
  • Thread(์ผ๊พผ)๋“ค์€ ๊ฐ๊ฐ ๋ช…๋ น์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ์ž์‹ ๋งŒ์˜ ๋ฉ”๋ชจ๋ฆฌ๊ณต๊ฐ„(Stack)์„ ํ• ๋‹น๋ฐ›๋Š”๋‹ค.
  • Java Thread
    • Java Main Thread๋ถ€ํ„ฐ ์‹คํ–‰๋˜๋ฉฐ JVM์— ์˜ํ•ด ์‹คํ–‰๋œ๋‹ค.
    • Java Main Thread : Java ํ”„๋กœ๊ทธ๋žจ์ด ์‹คํ–‰๋  ๋•Œ ๋ฌด์กฐ๊ฑด ์ฒ˜์Œ์— ๊ฐ™์ด ์‹คํ–‰๋˜๋Š” Thread์ด๋‹ค.

Multi Thread

Java๋Š” Main Thread๊ฐ€ main( ) ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰์‹œํ‚ค๋ฉด์„œ ์‹œ์ž‘์ด ๋œ๋‹ค.

  • Main Thread๋Š” ํ•„์š”์— ๋”ฐ๋ผ์„œ ์ž‘์—… Thread๋“ค์„ ์ƒ์„ฑํ•ด์„œ ๋ณ‘๋ ฌ๋กœ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.
  • Java๋Š” ๋ฉ€ํ‹ฐ Thread๋ฅผ ์ง€์›ํ•œ๋‹ค.
  • Java ํ”„๋กœ๊ทธ๋žจ์€ Main Thread์™ธ์— ๋‹ค๋ฅธ ์ž‘์—… Thread๋“ค์„ ์ƒ์„ฑํ•˜์—ฌ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์‹คํ–‰ํ๋ฆ„์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.
    • Main Thread ์•ˆ์—์„œ ๋งŒ๋“ค์–ด์„œ ์‹คํ–‰์‹œํ‚ค๋Š” ๊ฒƒ์ด๋‹ค.
  • ์žฅ์ 
    • ์—ฌ๋Ÿฌ ๊ฐœ์˜ Thread(์‹คํ–‰ ํ๋ฆ„)์„ ํ†ตํ•ด ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ž‘์—…์„ ๋™์‹œ์— ํ•  ์ˆ˜ ์žˆ์–ด์„œ ์„ฑ๋Šฅ์ด ์ข‹์•„์ง„๋‹ค.
    • Stack์„ ์ œ์™ธํ•œ ๋ชจ๋“  ์˜์—ญ์—์„œ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ณต์œ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ž์›์„ ๋ณด๋‹ค ํšจ์œจ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ์‘๋‹ต Thread์™€ ์ž‘์—… Thread๋ฅผ ๋ถ„๋ฆฌํ•˜์—ฌ ๋น ๋ฅด๊ฒŒ ์‘๋‹ต์„ ์ค„ ์ˆ˜ ์žˆ๋‹ค. (๋น„๋™๊ธฐ)
  • ๋‹จ์ 
    • Process์˜ ์ž์›์„ ๊ณต์œ ํ•˜๋ฉด์„œ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ž์›์„ ์„œ๋กœ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ•˜๋Š” ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ ์˜๋ฏธํ•œ๋‹ค.
    • ๊ต์ฐฉ์ƒํƒœ(Dead-Lock)์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

Thread์™€ Runnable

Thread

๋”๋ณด๊ธฐ
package week05.thread;

// 1. Thread Class๋ฅผ ์ด์šฉํ•˜๋Š” ๊ฒƒ (์ƒ์†)
//
public class TestThread extends Thread{
    @Override
    public void run () {
        // ์‹ค์ œ ์šฐ๋ฆฌ๊ฐ€ ์“ฐ๋ ˆ๋“œ์—์„œ ์ˆ˜ํ–‰ํ•  ์ž‘์—…
        for (int i = 0; i < 100; i++) {
            System.out.print("*");
        }
    }
}
  • ํ•ต์‹ฌ์€ run( ) ๋ฉ”์„œ๋“œ์ด๋‹ค.
  • run( ) ๋ฉ”์„œ๋“œ์— ์ž‘์„ฑ๋œ ์ฝ”๋“œ๊ฐ€ Thread๊ฐ€ ์ˆ˜ํ–‰ํ•  ์ž‘์—…์ด๋‹ค.

Runnable

๋”๋ณด๊ธฐ
package week05.thread;

public class TestRunnable implements Runnable{
    @Override
    public void run() {
        // Thread์—์„œ ์ˆ˜ํ–‰ํ•  ์ž‘์—… ์ •์˜!!
        for (int i = 0; i < 100; i++) {
            System.out.print("$");
        }
    }
}
  • ์—ฌ๊ธฐ์„œ์˜ run( ) ๋ฉ”์„œ๋“œ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ Thread๊ฐ€ ์ˆ˜ํ–‰ํ•  ์ž‘์—…์ด๋‹ค.
  • Java๋Š” ๋‹ค์ค‘ ์ƒ์†์„ ์ง€์›ํ•˜์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— Thread๋ฅผ ์ƒ์† ๋ฐ›์•„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ํ™•์žฅ์„ฑ์ด ๋งค์šฐ ๋–จ์–ด์ง„๋‹ค.
  • ํ•˜์ง€๋งŒ Runnable์€ ์ธํ„ฐํŽ˜์ด์Šค์ด๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค๋ฅธ ํ•„์š”ํ•œ ํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ ํ™•์žฅ์„ฑ์— ๋งค์šฐ ์œ ๋ฆฌํ•˜๋‹ค.

๋žŒ๋‹ค์‹

๋”๋ณด๊ธฐ
package week05.thread;

public class Main {
    public static void main(String[] args) {

        // ์ต๋ช… ํ•จ์ˆ˜์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
        Runnable task = () -> {
            int sum = 0;
            for (int i = 0; i < 50; i++) {
                sum += i;
                System.out.println(sum);
            }
            System.out.println(Thread.currentThread().getName() + " ์ตœ์ข… ํ•ฉ : " + sum);
        };

        Thread thread1 = new Thread(task);
        thread1.setName("thread1");
        Thread thread2 = new Thread(task);
        thread2.setName("thread2");

        thread1.start();
        thread2.start();
    }
}
  • run( ) ๋ฉ”์„œ๋“œ์— ์ž‘์„ฑํ–ˆ๋˜ Thread๊ฐ€ ์ˆ˜ํ–‰ํ•  ์ž‘์—…์„ ์‹คํ–‰ ๋ธ”๋ก { } ์•ˆ์— ์ž‘์„ฑํ•˜๋ฉด ๋œ๋‹ค.
  • setname( ) ๋ฉ”์„œ๋“œ๋Š” ์“ฐ๋ ˆ๋“œ์— ์ด๋ฆ„์„ ๋ถ€์—ฌํ•  ์ˆ˜ ์žˆ๋‹ค.
  • Thread.currentThread( ).getName( )์€ ํ˜„์žฌ ์‹คํ–‰ ์ค‘์ธ Thread์˜ ์ด๋ฆ„์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

๋ฐ๋ชฌ Thread์™€ ์‚ฌ์šฉ์ž Thread

๋ฐ๋ชฌ Thread

  • ๋ณด์ด์ง€ ์•Š๋Š” ๊ณณ(background)์—์„œ ์‹คํ–‰๋˜๋Š” ๋‚ฎ์€ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ฐ€์ง„ Thread๋ฅผ ๋งํ•œ๋‹ค.
    • ๋ณด์กฐ์ ์ธ ์—ญํ• ์„ ๋‹ด๋‹นํ•˜๋ฉฐ ๋Œ€ํ‘œ์ ์ธ ๋ฐ๋ชฌ Thread๋กœ๋Š” ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰ํ„ฐ(GC)๊ฐ€ ์žˆ๋‹ค.
๋”๋ณด๊ธฐ
package week05.thread.demon;

public class Main {
    public static void main(String[] args) {
        Runnable demon = () -> {
            for (int i = 0; i < 1000000; i++) {
                System.out.println(i + "๋ฒˆ์งธ demon");
            }
        };

        // ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋‚ฎ๋‹ค! -> ์ƒ๋Œ€์ ์œผ๋กœ ๋‹ค๋ฅธ Thread์— ๋น„ํ•ด ๋ฆฌ์†Œ์Šค๋ฅผ ์ ๊ฒŒ ํ• ๋‹น๋ฐ›๋Š”๋‹ค.
        Thread thread = new Thread(demon);
        thread.setDaemon(true);

        thread.start();

        for (int i = 0; i < 100; i++) {
            System.out.println(i + "๋ฒˆ์งธ task");
        }
    }
}
  • ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋‚ฎ๊ณ  ๋‹ค๋ฅธ Thread๊ฐ€ ๋ชจ๋‘ ์ข…๋ฃŒ๋˜๋ฉด ๊ฐ•์ œ ์ข…๋ฃŒ๋‹นํ•œ๋‹ค.

์‚ฌ์šฉ์ž Thread

  • ๋ณด์ด๋Š” ๊ณณ(foreground)์—์„œ ์‹คํ–‰๋˜๋Š” ๋†’์€ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ฐ€์ง„ Thread๋ฅผ ๋งํ•œ๋‹ค.
  • ํ”„๋กœ๊ทธ๋žจ ๊ธฐ๋Šฅ์„ ๋‹ด๋‹นํ•˜๋ฉฐ ๋Œ€ํ‘œ์ ์ธ ์‚ฌ์šฉ์ž Thread๋กœ๋Š” Main Thread๊ฐ€ ์žˆ๋‹ค.
  • ์‚ฌ์šฉ์ž Thread ๋งŒ๋“œ๋Š” ๋ฒ• : ๊ธฐ์กด์— ๋งŒ๋“ค์—ˆ๋˜ Thread๋“ค์ด ์ „๋ถ€ ์‚ฌ์šฉ์ž Thread์ด๋‹ค.

JVM์€ ์‚ฌ์šฉ์ž Thread์˜ ์ž‘์—…์ด ๋๋‚˜๋ฉด ๋ฐ๋ชฌ Thread๋„ ์ž๋™์œผ๋กœ ์ข…๋ฃŒ์‹œ์ผœ ๋ฒ„๋ฆฐ๋‹ค.


Thread ์šฐ์„  ์ˆœ์œ„์™€ Thread ๊ทธ๋ฃน

Thread ์šฐ์„  ์ˆœ์œ„

  • Thread ์ž‘์—…์˜ ์ค‘์š”๋„์— ๋”ฐ๋ผ์„œ Thread์˜ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๋ถ€์—ฌํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ํ•œ Process์— ์—ฌ๋Ÿฌ ๊ฐœ์˜ Thread๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค. ๋ชจ๋“  Thread๊ฐ€ ๋‹ค ๋˜‘๊ฐ™์ด ์ค‘์š”ํ•œ Thread๋Š” ์•„๋‹ ๊ฒƒ์ด๋‹ค. 
    • ์ž‘์—…์˜ ์ค‘์š”๋„๊ฐ€ ๋†’์„ ๋•Œ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๋†’๊ฒŒ ์ง€์ •ํ•˜๋ฉด ๋” ๋งŽ์€ ์ž‘์—…์‹œ๊ฐ„์„ ๋ถ€์—ฌ๋ฐ›์•„ ๋น ๋ฅด๊ฒŒ ์ฒ˜๋ฆฌ๋  ์ˆ˜ ์žˆ๋‹ค.
  • Thread๋Š” ์ƒ์„ฑ๋  ๋•Œ ์šฐ์„ ์ˆœ์œ„๊ฐ€ ์ •ํ•ด์ง„๋‹ค.
    • ์ตœ๋Œ€ ์šฐ์„ ์ˆœ์œ„ (MAX_PRIORITY) = 10
    • ์ตœ์†Œ ์šฐ์„ ์ˆœ์œ„ (MIN_PRIORITY) = 1
    • ๋ณดํ†ต ์šฐ์„ ์ˆœ์œ„ (NROM_PRIORITY) = 5
      • ๊ธฐ๋ณธ ๊ฐ’์ด ๋ณดํ†ต ์šฐ์„ ์ˆœ์œ„์ด๋‹ค.
    • ์šฐ์„ ์ˆœ์œ„์˜ ๋ฒ”์œ„๋Š” OS๊ฐ€ ์•„๋‹ˆ๋ผ JVM์—์„œ ์„ค์ •ํ•œ ์šฐ์„ ์ˆœ์œ„์ด๋‹ค.
  • Thread ์šฐ์„ ์ˆœ์œ„๋Š” setPriority( ) ๋ฉ”์„œ๋“œ๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
  • getPriority( ) ๋ฉ”์„œ๋“œ๋กœ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๋ฐ˜ํ™˜ํ•˜์—ฌ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
๋”๋ณด๊ธฐ
package week05.thread.priority;

public class Main {
    public static void main(String[] args) {
        Runnable task1 = () -> {
            for (int i = 0; i < 100; i++) {
                System.out.print("$");
            }
        };

        Runnable task2 = () -> {
            for (int i = 0; i < 100; i++) {
                System.out.print("*");
            }
        };

        Thread thread1 = new Thread(task1);
        thread1.setPriority(8);
        int threadPriority = thread1.getPriority();
        System.out.println("threadPriority = " + threadPriority);

        Thread thread2 = new Thread(task2);
        thread2.setPriority(2);

        thread1.start();
        thread2.start();
    }
}
  • Thread1์ด ๋ฆฌ์†Œ์Šค๋ฅผ ๋” ๋งŽ์ด ๊ฐ€์ ธ๊ฐ„๋‹ค. ๋” ๋นจ๋ฆฌ ๋๋‚  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๋‹ค.
    • ๋ฌด๊ฑฐ์šด ์ž‘์—…์„ ๋Œ๋ฆด ๋•Œ ๋น›์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

Thread ๊ทธ๋ฃน

์„œ๋กœ ๊ด€๋ จ์ด ์žˆ๋Š” thread๋“ค์„ ๊ทธ๋ฃน์œผ๋กœ ๋ฌถ์–ด์„œ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๋‹ค.

  • Thread๋“ค์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ๊ทธ๋ฃน์— ํฌํ•จ๋˜์–ด ์žˆ๋‹ค.
    • JVM์ด ์‹œ์ž‘๋˜๋ฉด system ๊ทธ๋ฃน์ด ์ƒ์„ฑ๋˜๊ณ  Thread๋“ค์€ ๊ธฐ๋ณธ์ ์œผ๋กœ system ๊ทธ๋ฃน์— ํฌํ•จ๋œ๋‹ค.
  • Main Thread๋Š” system ๊ทธ๋ฃน ํ•˜์œ„์— ์žˆ๋Š” main ๊ทธ๋ฃน์— ํฌํ•จ๋œ๋‹ค.
  • ๋ชจ๋“  Thread๋“ค์€ ๋ฐ˜๋“œ์‹œ ํ•˜๋‚˜์˜ ๊ทธ๋ฃน์— ํฌํ•จ๋˜์–ด ์žˆ์–ด์•ผ ํ•œ๋‹ค. → ์ž๋™์œผ๋กœ main ๊ทธ๋ฃน์— ํฌํ•จ๋œ๋‹ค.
๋”๋ณด๊ธฐ
package week05.thread.group;

public class Main {
    public static void main(String[] args) {
        Runnable task = () -> {
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    Thread.sleep(1000);
                    System.out.println(Thread.currentThread().getName());
                } catch (InterruptedException e) {
                    break;
                }
            }
            System.out.println(Thread.currentThread().getName() + " Interrupted");
        };

        // ThreadGroup ํด๋ž˜์Šค๋กœ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
        ThreadGroup group1 = new ThreadGroup("Group1");

        // Thread ๊ฐ์ฒด ์ƒ์„ฑ์‹œ ์ฒซ๋ฒˆ์งธ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋„ฃ์–ด์ค๋‹ˆ๋‹ค.
        // Thread(ThreadGroup group, Runnable target, String name)
        Thread thread1 = new Thread(group1, task, "Thread 1");
        Thread thread2 = new Thread(group1, task, "Thread 2");

        // Thread์— ThreadGroup ์ด ํ• ๋‹น๋œ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
        System.out.println("Group of thread1 : " + thread1.getThreadGroup().getName());
        System.out.println("Group of thread2 : " + thread2.getThreadGroup().getName());

        thread1.start();
        thread2.start();

        try {
            // ํ˜„์žฌ ์“ฐ๋ ˆ๋“œ๋ฅผ ์ง€์ •๋œ ์‹œ๊ฐ„๋™์•ˆ ๋ฉˆ์ถ”๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // interrupt()๋Š” ์ผ์‹œ์ •์ง€ ์ƒํƒœ์ธ ์“ฐ๋ ˆ๋“œ๋ฅผ ์‹คํ–‰๋Œ€๊ธฐ ์ƒํƒœ๋กœ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
        group1.interrupt();

    }
}

Thread ์ƒํƒœ์™€ ์ œ์–ด

Thread ์ƒํƒœ

Thread๋ฅผ ์ •๋ฆฌํ•œ ํ‘œ

์ƒํƒœ Enum(์ƒ์ˆ˜) ์„ค๋ช…
๊ฐ์ฒด ์ƒ์„ฑ NEW Thread ๊ฐ์ฒด ์ƒ์„ฑ, ์•„์ง start( ) ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ์ „์˜ ์ƒํƒœ
์‹คํ–‰ ๋Œ€๊ธฐ RUNNABLE ์‹คํ–‰ ์ƒํƒœ๋กœ ์–ธ์ œ๋“ ์ง€ ๊ฐˆ ์ˆ˜ ์žˆ๋Š” ์ƒํƒœ
์ผ์‹œ์ •์ง€ WAITING ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ํ†ต์ง€(notify)ํ•  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๋Š” ์ƒํƒœ
์ผ์‹œ์ •์ง€ TIMED_WAITING ์ฃผ์–ด์ง„ ์‹œ๊ฐ„ ๋™์•ˆ ๊ธฐ๋‹ค๋ฆฌ๋Š” ์ƒํƒœ
์ผ์‹œ์ •์ง€ BLOCKED ์‚ฌ์šฉํ•˜๊ณ ์ž ํ•˜๋Š” ๊ฐ์ฒด์˜ Lock์ด ํ’€๋ฆด ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๋Š” ์ƒํƒœ
์ข…๋ฃŒ TERMINATED Thread์˜ ์ž‘์—…์ด ์ข…๋ฃŒ๋œ ์ƒํƒœ

Thread ์ œ์–ด


sleep( ), interrupt( )

sleep( )

  • ํ˜„์žฌ Thread๋ฅผ ์ง€์ •๋œ ์‹œ๊ฐ„๋™์•ˆ ๋ฉˆ์ถ”๊ฒŒ ํ•œ๋‹ค.
  • Thread ์ž๊ธฐ์ž์‹ ์— ๋Œ€ํ•ด์„œ๋งŒ ๋ฉˆ์ถ”๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค.
๋”๋ณด๊ธฐ
package week05.thread.stat.sleep;

public class Main {
    public static void main(String[] args) {
        Runnable task = () -> {
            try {
                // (1) ์˜ˆ์™ธ์ฒ˜๋ฆฌ ํ•„์ˆ˜!
                // - interrupt() ๋ฅผ ๋งŒ๋‚˜๋ฉด ๋‹ค์‹œ ์‹คํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์—
                // - InterruptedException์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.
                // (2) ํŠน์ • Thread ์ง€๋ชฉ ๋ถˆ๊ฐ€
                Thread.sleep(2000);  // TIMED_WAITING (์ฃผ์–ด์ง„ ์‹œ๊ฐ„๋™์•ˆ๋งŒ ๊ธฐ๋‹ค๋ฆฌ๋Š” ์ƒํƒœ)


            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("task : " + Thread.currentThread().getName());
        };

        Thread thread = new Thread(task, "Thread");  // NEW
        thread.start();  // NEW -> RUNNABLE

        try {
            // 1์ดˆ๊ฐ€ ์ง€๋‚˜๊ณ  ๋‚˜๋ฉด runnable ์ƒํƒœ๋กœ ๋ณ€ํ•˜์—ฌ ๋‹ค์‹œ ์‹คํ–‰๋œ๋‹ค!
            // ํŠน์ • ์Šค๋ ˆ๋“œ๋ฅผ ์ง€๋ชฉํ•ด์„œ ๋ฉˆ์ถ”๊ฒŒ ํ•˜๋Š” ๊ฒƒ์€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค!
            // Static member 'java.lang.Thread.sleep(long)' accessed via instance reference
            thread.sleep(1000);
            System.out.println("sleep(1000) : " + Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

interrupt( )

  • ์ผ์‹œ์ •์ง€ ์ƒํƒœ์ธ Thread๋ฅผ ์‹คํ–‰๋Œ€๊ธฐ ์ƒํƒœ๋กœ ๋งŒ๋“ ๋‹ค.
๋”๋ณด๊ธฐ
package week05.thread.stat.interrupt;

public class Main {
    public static void main(String[] args) {
        Runnable task = () -> {
            // interrupted ์ƒํƒœ๋ฅผ ์ฒดํฌํ•ด์„œ ์ฒ˜๋ฆฌํ•˜๋ฉด ์˜ค๋ฅ˜๋ฅผ ๋ฐฉ์ง€
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    Thread.sleep(1000);
                    System.out.println(Thread.currentThread().getName());
                } catch (InterruptedException e) {
                    break;
                }
            }
            System.out.println("task : " + Thread.currentThread().getName());
        };

        Thread thread = new Thread(task, "Thread");
        thread.start();

        thread.interrupt();

        System.out.println("thread.isInterrupted() = " + thread.isInterrupted());

    }
}

join( )

  • ์ •ํ•ด์ง„ ์‹œ๊ฐ„ ๋™์•ˆ ์ง€์ •ํ•œ Thread๊ฐ€ ์ž‘์—…ํ•˜๋Š” ๊ฒƒ์„ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.
  • ์‹œ๊ฐ„์„ ์ง€์ •ํ•˜์ง€ ์•Š์•˜์„ ๋•Œ๋Š” ์ง€์ •ํ•œ Thread์˜ ์ž‘์—…์ด ๋๋‚  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.
๋”๋ณด๊ธฐ
package week05.thread.stat.join;

// ์ •ํ•ด์ง„ ์‹œ๊ฐ„ ๋™์•ˆ ์ง€์ •ํ•œ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ž‘์—…ํ•˜๋Š” ๊ฒƒ์„ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.
// - ์‹œ๊ฐ„์„ ์ง€์ •ํ•˜์ง€ ์•Š์•˜์„ ๋•Œ๋Š” ์ง€์ •ํ•œ Thread์˜ ์ž‘์—…์ด ๋๋‚  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.
public class Main {
    public static void main(String[] args) {
        Runnable task = () -> {
            try {
                Thread.sleep(5000); // 5์ดˆ
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };

        Thread thread = new Thread(task, "thread");  // NEW

        thread.start();  // NEW -> Runnable

        long start = System.currentTimeMillis();  // ๋ช‡ ์ดˆ์ •๋„ ์†Œ์š”๋๋Š”์ง€ ๊ณ„์‚ฐํ•ด๋ณด๊ธฐ ์œ„ํ•ด ๋ฐ›์•„์˜จ๋‹ค.

        try {
            // ์‹œ๊ฐ„์„ ์ง€์ •ํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— thread๊ฐ€ ์ž‘์—…์„ ๋๋‚ผ ๋•Œ๊นŒ์ง€ main thread๋Š” ๊ธฐ๋‹ค๋ฆฌ๊ฒŒ ๋œ๋‹ค.
            thread.join();

        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // thread ์˜ ์†Œ์š”์‹œ๊ฐ„์ธ 5000ms ๋™์•ˆ main ์“ฐ๋ ˆ๋“œ๊ฐ€ ๊ธฐ๋‹ค๋ ธ๊ธฐ ๋•Œ๋ฌธ์— 5000์ด์ƒ์ด ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค.
        System.out.println("์†Œ์š”์‹œ๊ฐ„ = " + (System.currentTimeMillis() - start));
    }
}

yield( )

  • ๋‚จ์€ ์‹œ๊ฐ„์„ ๋‹ค์Œ Thread์—๊ฒŒ ์–‘๋ณดํ•˜๊ณ  Thread ์ž์‹ ์€ ์‹คํ–‰๋Œ€๊ธฐ ์ƒํƒœ๊ฐ€ ๋œ๋‹ค.
๋”๋ณด๊ธฐ
package week05.thread.stat.yield;

// ๋‚จ์€ ์‹œ๊ฐ„์„ ๋‹ค์Œ Thread์—๊ฒŒ ์–‘๋ณดํ•˜๊ณ  Thread ์ž์‹ ์€ ์‹คํ–‰๋Œ€๊ธฐ ์ƒํƒœ๊ฐ€ ๋œ๋‹ค.

// thread1๊ณผ thread2๊ฐ€ ๊ฐ™์ด 1์ดˆ์— ํ•œ ๋ฒˆ์”ฉ ์ถœ๋ ฅ๋˜๋‹ค๊ฐ€
// 5์ดˆ ๋’ค์— thread1์—์„œ InterruptedException์ด
// ๋ฐœ์ƒํ•˜๋ฉด์„œ Thread.yield(); ์ด ์‹คํ–‰๋˜์–ด thread1์€
// ์‹คํ–‰๋Œ€๊ธฐ ์ƒํƒœ๋กœ ๋ณ€๊ฒฝ๋˜๋ฉด์„œ ๋‚จ์€ ์‹œ๊ฐ„์€ thread2์—๊ฒŒ ์–‘๋ณด๋œ๋‹ค.

public class Main {
    public static void main(String[] args) {
        Runnable task = () -> {
            try {
                for (int i = 0; i < 10; i++) {
                    Thread.sleep(1000);
                    System.out.println(Thread.currentThread().getName());
                }
            } catch (InterruptedException e) {
                Thread.yield();
            }
        };

        Thread thread1 = new Thread(task, "thread1");  // NEW
        Thread thread2 = new Thread(task, "thread2");  // NEW

        thread1.start();  // NEW -> Runnable
        thread2.start();  // NEW -> Runnable

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        thread1.interrupt();

    }
}

synchronized( )

  • Multi Thread์˜ ๊ฒฝ์šฐ ์—ฌ๋Ÿฌ Thread๊ฐ€ ํ•œ ํ”„๋กœ์„ธ์Šค์˜ ์ž์›์„ ๊ณต์œ ํ•ด์„œ ์ž‘์—…ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์„œ๋กœ์—๊ฒŒ ์˜ํ–ฅ์„ ์ค„ ์ˆ˜ ์žˆ๋‹ค.
    ์ด๋กœ ์ธํ•ด ์žฅ์• ๋‚˜ ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์ด๋Ÿฌํ•œ ์ผ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ํ•œ Thread๊ฐ€ ์ง„ํ–‰ ์ค‘์ธ ์ž‘์—…์„ ๋‹ค๋ฅธ Thread๊ฐ€ ์นจ๋ฒ”ํ•˜์ง€ ๋ชปํ•˜๋„๋ก ๋ง‰๋Š” ๊ฒƒ์ด๋‹ค.
  • ๋™๊ธฐํ™”๋ฅผ ํ•˜๋ ค๋ฉด ๋‹ค๋ฅธ Thread์˜ ์นจ๋ฒ”์„ ๋ง‰์•„์•ผํ•˜๋Š” ์ฝ”๋“œ๋“ค์„ '์ž„๊ณ„์˜์—ญ'์œผ๋กœ ์„ค์ •ํ•˜๋ฉด ๋œ๋‹ค.
  • ์ž„๊ณ„์˜์—ญ์—๋Š” Lock์„ ๊ฐ€์ง„ ๋‹จ ํ•˜๋‚˜์˜ Thread๋งŒ ์ถœ์ž…์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
    • ์ž„๊ณ„์˜์—ญ์€ ํ•œ๋ฒˆ์— ๋‹จ ํ•˜๋‚˜์˜ Thread๋งŒ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
  • ์‹คํ–‰ํ•  ๋ฉ”์„œ๋“œ ๋˜๋Š” ์‹คํ–‰ํ•  ์ฝ”๋“œ ๋ฌถ์Œ ์•ž์— ๋ถ™์—ฌ์„œ ์ž„๊ณ„์˜์—ญ์„ ์ง€์ •ํ•˜์—ฌ ๋‹ค๋ฅธ Thread์˜ ์นจ๋ฒ”์„ ๋ง‰์„ ์ˆ˜ ์žˆ๋‹ค.
๋”๋ณด๊ธฐ
package week05.thread.stat.sync;

public class Main {
    public static void main(String[] args) {
        AppleStore appleStore = new AppleStore();

        Runnable task = () -> {
            while (appleStore.getStoredApple() > 0) {
                appleStore.eatApple();
                System.out.println("๋‚จ์€ ์‚ฌ๊ณผ์˜ ์ˆ˜ = " + appleStore.getStoredApple());
            }

        };

        // 3๊ฐœ์˜ thread๋ฅผ ํ•œ๊บผ๋ฒˆ์— ๋งŒ๋“ค์–ด์„œ start๋ฅผ ํ•ด๋ฒ„๋ฆผ!!
        // ์ƒ์„ฑ(NEW)๊ณผ ๋™์‹œ์— start(NEW -> Runnable)
        for (int i = 0; i < 3; i++) {
            // thread A, B, C
            new Thread(task).start();
        }
    }
}

class AppleStore {
    private int storedApple = 10;

    public int getStoredApple() {
        return storedApple;
    }

    public void eatApple() {
        synchronized (this) {
            if(storedApple > 0) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                storedApple -= 1;
            }
        }
    }
}

wait( ), notify( ) → ๋‘˜์€ ์Œ์ด๋‹ค. ํ•ญ์ƒ ๊ฐ™์ด ์‚ฌ์šฉํ•œ๋‹ค.

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

wait( )

  • ์‹คํ–‰ ์ค‘์ด๋˜ Thread๋Š” ํ•ด๋‹น ๊ฐ์ฒด์˜ ๋Œ€๊ธฐ์‹ค(waiting pool)์—์„œ ํ†ต์ง€๋ฅผ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.

notify( )

  • ํ•ด๋‹น ๊ฐ์ฒด์˜ ๋Œ€๊ธฐ์‹ค(waiting pool)์— ์žˆ๋Š” ๋ชจ๋“  Thread ์ค‘์—์„œ ์ž„์˜์˜ Thread๋งŒ ํ†ต์ง€๋ฅผ ๋ฐ›๋Š”๋‹ค. (random์œผ๋กœ ๋ฐ›๋Š”๋‹ค.)
๋”๋ณด๊ธฐ
package week05.thread.stat.waitnotify;

import java.util.ArrayList;
import java.util.List;

public class Main {
    public static String[] itemList = {
            "MacBook", "IPhone", "AirPods", "iMac", "Mac mini"
    };
    public static AppleStore appleStore = new AppleStore();
    public static final int MAX_ITEM = 5;

    public static void main(String[] args) {

        // ๊ฐ€๊ฒŒ ์ ์›
        Runnable StoreClerk = () -> {
            while (true) {
                // 0๋ถ€ํ„ฐ 4 ์‚ฌ์ด์˜ ์ •์ˆ˜ ์ค‘, Randomํ•œ ๊ฐ’์„ ๋ฝ‘์•„๋‚ด๊ธฐ ์œ„ํ•จ.
                int randomItem = (int) (Math.random() * MAX_ITEM);

                // restock : ์žฌ๊ณ ๋ฅผ ๋„ฃ๋Š” ๋ฉ”์„œ๋“œ
                appleStore.restock(itemList[randomItem]);
                try {
                    Thread.sleep(50);
                } catch (InterruptedException ignored) {
                }
            }
        };

        // ๊ณ ๊ฐ
        Runnable Customer = () -> {
            while (true) {
                try {
                    Thread.sleep(77);
                } catch (InterruptedException ignored) {
                }

                int randomItem = (int) (Math.random() * MAX_ITEM);

                // sale : ํŒ๋งคํ•˜๋Š” ๋ฉ”์„œ๋“œ
                appleStore.sale(itemList[randomItem]);
                System.out.println(Thread.currentThread().getName() + " Purchase Item " + itemList[randomItem]);
            }
        };


        new Thread(StoreClerk, "StoreClerk").start();
        new Thread(Customer, "Customer1").start();
        new Thread(Customer, "Customer2").start();

    }
}

class AppleStore {
    private List<String> inventory = new ArrayList<>();

    public void restock(String item) {
        synchronized (this) {
            while (inventory.size() >= Main.MAX_ITEM) {
                System.out.println(Thread.currentThread().getName() + " Waiting!");
                try {
                    wait(); // ์žฌ๊ณ ๊ฐ€ ๊ฝ‰ ์ฐจ์žˆ์–ด์„œ ์žฌ์ž…๊ณ ํ•˜์ง€ ์•Š๊ณ  ๊ธฐ๋‹ค๋ฆฌ๋Š” ์ค‘!
                    Thread.sleep(333);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            // ์žฌ์ž…๊ณ 
            inventory.add(item);
            notify(); // ์žฌ์ž…๊ณ  ๋˜์—ˆ์Œ์„ ๊ณ ๊ฐ์—๊ฒŒ ์•Œ๋ ค์ฃผ๊ธฐ
            System.out.println("Inventory ํ˜„ํ™ฉ: " + inventory.toString());
        }
    }

    public synchronized void sale(String itemName) {
        while (inventory.size() == 0) {
            System.out.println(Thread.currentThread().getName() + " Waiting!");
            try {
                wait(); // ์žฌ๊ณ ๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— ๊ณ ๊ฐ ๋Œ€๊ธฐ์ค‘
                Thread.sleep(333);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        while (true) {
            // ๊ณ ๊ฐ์ด ์ฃผ๋ฌธํ•œ ์ œํ’ˆ์ด ์žˆ๋Š”์ง€ ํ™•์ธ
            for (int i = 0; i < inventory.size(); i++) {
                if (itemName.equals(inventory.get(i))) {
                    inventory.remove(itemName);
                    notify(); // ์ œํ’ˆ ํ•˜๋‚˜ ํŒ”๋ ธ์œผ๋‹ˆ ์žฌ์ž…๊ณ  ํ•˜๋ผ๊ณ  ์•Œ๋ ค์ฃผ๊ธฐ
                    return; // ๋ฉ”์„œ๋“œ ์ข…๋ฃŒ
                }
            }

            // ๊ณ ๊ฐ์ด ์ฐพ๋Š” ์ œํ’ˆ์ด ์—†์„ ๊ฒฝ์šฐ
            try {
                System.out.println(Thread.currentThread().getName() + " Waiting!");
                wait();
                Thread.sleep(333);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}

Lock

  • synchronized ๋ธ”๋Ÿญ์œผ๋กœ ๋™๊ธฐํ™”ํ•˜๋ฉด ์ž๋™์ ์œผ๋กœ Lock์ด ๊ฑธ๋ฆฌ๊ณ  ํ’€๋ฆฌ์ง€๋งŒ, ๊ฐ™์€ ๋ฉ”์„œ๋“œ ๋‚ด์—์„œ๋งŒ Lock์„ ๊ฑธ ์ˆ˜ ์žˆ๋‹ค๋Š” ์ œ์•ฝ์ด ์žˆ๋‹ค.
    ์ด ์ œ์•ฝ์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด Lock ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
  • ReentrantLock
    • ์žฌ์ง„์ž… ๊ฐ€๋Šฅํ•œ Lock, ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ธ ๋ฐฐํƒ€ Lock
    • ํŠน์ • ์กฐ๊ฑด์—์„œ Lock์„ ํ’€๊ณ , ๋‚˜์ค‘์— ๋‹ค์‹œ Lock์„ ์–ป์–ด ์ž„๊ณ„์˜์—ญ์œผ๋กœ ์ง„์ž…์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
๋”๋ณด๊ธฐ
public class MyClass {
    private Object lock1 = new Object();
    private Object lock2 = new Object();
    
    public void methodA() {
        synchronized (lock1) {
            methodB();
        }
    }
    
    public void methodB() {
        synchronized (lock2) {
            // do something
            methodA();
        }
    }
}
  • methodA์—์„œ ์ด๋ฏธ Lock1์„ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฏ€๋กœ lock2๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ์ƒํƒœ๊ฐ€ ๋˜์–ด ๋ฐ๋“œ๋ฝ์ด ๋ฐœ์ƒํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋‹ค.
  • ํ•˜์ง€๋งŒ ReentrantLock์„ ์‚ฌ์šฉํ•˜๋ฉด, ๊ฐ™์€ Thread๊ฐ€ ์ด๋ฏธ Lock์„ ๊ฐ€์ง€๊ณ  ์žˆ๋”๋ผ๋„ Lock์„ ์œ ์ง€ํ•˜๋ฉฐ ๊ณ„์† ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— Dead-Lock์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • ์ฝ”๋“œ์˜ ์œ ์—ฐ์„ฑ์„ ๋†’์ผ ์ˆ˜ ์žˆ๋‹ค.
  • ReentrantReadWriteLock
    • ์ฝ๊ธฐ๋ฅผ ์œ„ํ•œ Lock๊ณผ ์“ฐ๊ธฐ๋ฅผ ์œ„ํ•œ Lock์„ ๋”ฐ๋กœ ์ œ๊ณตํ•œ๋‹ค.
    • ์ฝ๊ธฐ์—๋Š” ๊ณต์œ ์ ์ด๊ณ , ์“ฐ๊ธฐ์—๋Š” ๋ฒ ํƒ€์ ์ธ Lock์ด๋‹ค.
    • ์ฝ๊ธฐ Lock์ด ๊ฑธ๋ ค์žˆ์œผ๋ฉด ๋‹ค๋ฅธ Thread๋“ค๋„ ์ฝ๊ธฐ Lock์„ ์ค‘๋ณต์œผ๋กœ ๊ฑธ๊ณ  ์ฝ๊ธฐ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค. (read-only)
    • ์ฝ๊ธฐ Lock์ด ๊ฑธ๋ ค์žˆ๋Š” ์ƒํƒœ์—์„œ ์“ฐ๊ธฐ Lock์„ ๊ฑฐ๋Š” ๊ฒƒ์€ ํ—ˆ์šฉ๋˜์ง€ ์•Š๋Š”๋‹ค.
  • StampedLock
    • ReentrantReadWriteLock์— ๋‚™๊ด€์ ์ธ Lock์˜ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ–ˆ๋‹ค.
      • ๋‚™๊ด€์ ์ธ Lock : ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ธฐ ์ „์— ๋ฝ์„ ๊ฑธ์ง€ ์•Š๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.
      • ๋‚™๊ด€์ ์ธ Lock์„ ์‚ฌ์šฉํ•˜๋ฉด ์ฝ๊ธฐ์™€ ์“ฐ๊ธฐ ์ž‘์—… ๋ชจ๋‘๊ฐ€ ๋น ๋ฅด๊ฒŒ ์ฒ˜๋ฆฌ๋œ๋‹ค. → ์—ฌ๋Ÿฌ Thread๊ฐ€ ๋™์‹œ์— ๋ณ€๊ฒฝํ•˜๋ ค๊ณ  ํ•  ๋•Œ๋Š” ์ ํ•ฉํ•˜์ง€ ์•Š๋‹ค.

Condition

  • waiting pool ๋‚ด Thread๋ฅผ ๊ตฌ๋ถ„ํ•˜์ง€ ๋ชปํ•œ๋‹ค๋Š” ๊ฒƒ์„ ํ•ด๊ฒฐํ•œ ๊ฒƒ์ด Condition์ด๋‹ค.
  • Condition์€ waiting pool ๋‚ด์˜ Thread๋ฅผ ๋ถ„๋ฆฌํ•˜์—ฌ ํŠน์ • ์กฐ๊ฑด์ด ๋งŒ์กฑ๋  ๋•Œ๋งŒ ๊นจ์šฐ๋„๋ก ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ReentrantLock ํด๋ž˜์Šค์™€ ํ•จ๊ป˜ ์‚ฌ์šฉ๋œ๋‹ค.
  • ๋”ฐ๋ผ์„œ Condition์„ ์‚ฌ์šฉํ•˜๋ฉด wait( )๊ณผ notify( )์˜ ๋ฌธ์ œ์ ์„ ๋ณด์™„ํ•  ์ˆ˜ ์žˆ๋‹ค.
๋”๋ณด๊ธฐ
public class Main {
public static final int MAX_TASK = 5;

private ReentrantLock lock = new ReentrantLock();

// lock์œผ๋กœ condition ์ƒ์„ฑ
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();

private ArrayList<String> tasks = new ArrayList<>();

// ์ž‘์—… ๋ฉ”์„œ๋“œ
public void addMethod(String task) {
			lock.lock(); // ์ž„๊ณ„์˜์—ญ ์‹œ์ž‘
	
			try {
				while(tasks.size() >= MAX_TASK) {
						String name = Thread.currentThread().getName();
						System.out.println(name+" is waiting.");
						try {
							condition1.await(); // wait(); condition1 ์“ฐ๋ ˆ๋“œ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.
							Thread.sleep(500);
						} catch(InterruptedException e) {}	
				}
	
				tasks.add(task);
				condition2.signal(); // notify();  ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์žˆ๋Š” condition2๋ฅผ ๊นจ์›Œ์ค๋‹ˆ๋‹ค.
				System.out.println("Tasks:" + tasks.toString());
			} finally {
				lock.unlock(); // ์ž„๊ณ„์˜์—ญ ๋
			}
		}
	}

๋ชจ๋˜ ์ž๋ฐ” ์•Œ์•„๋ณด๊ธฐ

  • ์‹œ์žฅ์—์„œ ํ”„๋กœ๊ทธ๋ž˜๋จธ๊ฐ€ ํ•ด๊ฒฐํ•ด์•ผ ํ•˜๋Š” ๋ฌธ์ œ๋Š” ๊ณ„์† ๋ณ€ํ™”ํ•œ๋‹ค.
  • ๋ฌธ์ œ๊ฐ€ ๋ณ€ํ™”ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์— ์š”๊ตฌ๋˜๋Š” ๊ธฐ๋Šฅ๋“ค๋„ ๋ณ€ํ™”ํ•œ๋‹ค.
  • ์˜ˆ๋ฅผ ๋“ค์–ด C/C++ ๊ฐ™์€ ์–ธ์–ด๋“ค์€ ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰์— ๋Œ€ํ•œ ๋น„์šฉ์ด ํฌ์ง€ ์•Š๊ณ , ํ•˜๋“œ์›จ์–ด์ ์ธ ๋ณดํŽธ์„ฑ, ํ˜ธํ™˜์„ฑ์— ํฐ ์žฅ์ ์„ ๊ฐ€์ง€๊ณ  ์žˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์‹œ์žฅ์—์„œ ๊ฐ€์žฅ ์ง€๋ฐฐ์ ์ธ ์ž…์ง€๋ฅผ ์ฐจ์ง€ํ–ˆ์—ˆ์Šต๋‹ˆ๋‹ค.
  • ํ•˜์ง€๋งŒ ํŠน์œ ์˜ ๋‚œ์ด๋„์™€ ๋‹ค๋ฅธ ์š”์ธ๋“ค์˜ ์˜ํ–ฅ์œผ๋กœ ์˜ˆ๊ธฐ์น˜ ์•Š๊ฒŒ ์ข…๋ฃŒ๋˜๊ฑฐ๋‚˜, ๋ณด์•ˆ ์ด์Šˆ๊ฐ€ ๋งŽ์•„์ง€๋Š” ๋“ฑ ์•ˆ์ •์„ฑ์ด ๋–จ์–ด์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
  • ๊ทธ๋Ÿฌ๋˜ ์™€์ค‘์— ํ•˜๋“œ์›จ์–ด๋Š” ๊พธ์ค€ํ•œ ์ง„ํ™”๋ฅผ ๊ฑฐ๋“ญํ–ˆ๊ณ , ๊ทธ ์ง„ํ™”์˜ ๊ฒฐ๊ณผ๋กœ ํ”„๋กœ๊ทธ๋žจ์„ ์‹คํ–‰์‹œํ‚ค๋Š” ์ž์›์„ ๋” ๋งŽ์ด ์‚ฌ์šฉํ•ด๋„ ๊ดœ์ฐฎ์€ ํ™˜๊ฒฝ์—์„œ๋Š”, ๋” ์•ˆ์ •์„ฑ์ด ๋†’์€ c#, java์™€ ๊ฐ™์€ ์–ธ์–ด๋“ค์ด ๊ฐ๊ด‘๋ฐ›๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
  • ์ด์ฒ˜๋Ÿผ ์‹œ์žฅ์˜ ์ƒํ™ฉ์— ๋”ฐ๋ผ์„œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๋Š” ์ƒˆ๋กœ์šด ๋Œ€์•ˆ์œผ๋กœ ๋“ฑ์žฅํ•˜๊ณ , ์ ์‘ํ•ด์„œ ์‚ด์•„๋‚จ๊ฑฐ๋‚˜, ์ ์‘ํ•˜์ง€ ๋ชปํ•ด์„œ ๋„ํƒœ๋˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.

๋žŒ๋‹ค ์ต๋ช…ํ•จ์ˆ˜

  • ๋žŒ๋‹ค๋Š” ์ต๋ช…ํ•จ์ˆ˜๋ฅผ ์ง€์นญํ•˜๋Š” ๋ง์ด๋‹ค.
  • ์ผ๊ธ‰ ๊ฐ์ฒด๋กœ ์ทจ๊ธ‰๋œ๋‹ค. → ์ผ๊ธ‰ ๊ฐ’(ํ•จ์ˆ˜ = ๊ฐ์ฒด(๋ณ€์ˆ˜))์œผ๋กœ ๋ฐ›๋Š”๋‹ค๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€ ๋งฅ๋ฝ

์ŠคํŠธ๋ฆผ

  • ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ์—ฐ์‚ฐ์„ ์ง€์›ํ•˜๋„๋ก ์†Œ์Šค์—์„œ ์ถ”์ถœ๋œ ์—ฐ์†๋œ ์š”์†Œ์ด๋‹ค.
  • ์ปฌ๋ ‰์…˜์˜ ๋ฐ˜๋ณต์„ ๋ฉ‹์ง€๊ฒŒ ์ฒ˜๋ฆฌํ•˜๋Š” ์ผ์ข…์˜ ๊ธฐ๋Šฅ์ด์ž, Multi Thread ๊ด€๋ จ ์ฝ”๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์•„๋„ ์•Œ์•„์„œ ๋ณ‘๋ ฌ๋กœ ์ถ”๊ฐ€ํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.

์‚ฌ์šฉ ์˜ˆ์‹œ ์ฝ”๋“œ

๋”๋ณด๊ธฐ
package week05.thread.modern;

import java.util.ArrayList;
import java.util.List;

// ์ฃผ์ฐจ์žฅ ์˜ˆ์ œ
// ํ‹ฐ์ผ“, ํŒŒํ‚น๋จธ๋‹ˆ -> ์ฃผ์ฐจํ•˜๊ฒŒ ํ•˜๋Š” ์˜ˆ์ œ
public class LambdaAndStream {
    public static void main(String[] args) {

        // ์ฃผ์ฐจ๋Œ€์ƒ ์ฐจ๋Ÿ‰
        ArrayList<Car> carsWantToPark = new ArrayList<>();

        // ์ฃผ์ฐจ์žฅ
        ArrayList<Car> parkingLot = new ArrayList<>();

        // ์ฃผ๋ง์ฃผ์ฐจ์žฅ
        ArrayList<Car> weekendParkingLot = new ArrayList<>();

        // 5๊ฐœ์˜ car instance
        Car car1 = new Car("Benz", "Class E", true, 0);
        Car car2 = new Car("BMW", "Series 7", false, 100);
        Car car3 = new Car("BMW", "X9", false, 0);
        Car car4 = new Car("Audi", "A7", true, 0);
        Car car5 = new Car("Hyundai", "Ionic 6", false, 10000);

        carsWantToPark.add(car1);
        carsWantToPark.add(car2);
        carsWantToPark.add(car3);
        carsWantToPark.add(car4);
        carsWantToPark.add(car5);



        //        parkingLot.addAll(parkingCarWithTicket(carsWantToPark));
        parkingLot.addAll(parkCars(carsWantToPark, Car::hasTicket));

        //        parkingLot.addAll(parkingCarWithMoney(carsWantToPark));
        parkingLot.addAll(parkCars(carsWantToPark, Car::noTicketHasMoney));

        // ์ต๋ช…ํ•จ์ˆ˜ ์ ์šฉ
        parkingLot.addAll(parkCars(carsWantToPark, (Car car) -> car.hasParkingTicket() && car.getParkingMoney() > 1000));

        for (Car car : parkingLot) {
            System.out.println("Parked Car : " + car.getCompany() + "-" + car.getModel());
        }


    }

    // ํƒ€์ž…!!! -> (ํ•จ์ˆ˜ํ˜•) ์ธํ„ฐํŽ˜์ด์Šค
    // ์ธํ„ฐํŽ˜์ด์Šค๋Š” ํƒ€์ž… ์—ญํ• ์„ ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ! (๋ฉ€ํ‹ฐ ๋ฆฌ๋ชจ์ปจ ์˜ˆ์ œ)
    // ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค : ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋ฅผ ๋”ฑ ํ•˜๋‚˜๋งŒ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค!
//    public exampleMethod (int parameter1, ??? parameterFunction) {
//        parameterFunction~~~
//    }

//    public static List<Car> parkingCarWithTicket(List<Car> carsWantToPark) {
//        ArrayList<Car> cars = new ArrayList<>();
//
//        for (Car car : carsWantToPark) {
//            if (car.hasParkingTicket()) {
//                cars.add(car);
//            }
//        }
//
//        return cars;
//    }
//
//    public static List<Car> parkingCarWithMoney(List<Car> carsWantToPark) {
//        ArrayList<Car> cars = new ArrayList<>();
//
//        for (Car car : carsWantToPark) {
//            if (!car.hasParkingTicket() && car.getParkingMoney() > 1000) {
//                cars.add(car);
//            }
//        }
//
//        return cars;
//
//    }

    // ์œ„์˜ ๋‘ ๋ฉ”์„œ๋“œ๋ฅผ ํ•˜๋‚˜๋กœ!! : ๋‚ด๋ถ€ ์ฃผ์š” ๋กœ์ง์„ ํ•จ์ˆ˜๋กœ ์ „๋‹ฌ๋ฐ›์ž
    public static List<Car> parkCars(List<Car> carsWantToPark, Predicate<Car> function) {
        List<Car> cars = new ArrayList<>();

        for (Car car : carsWantToPark) {
            // ์ „๋‹ฌ๋œ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌํ˜„
            if (function.test(car)) {
                cars.add(car);
            }
        }

        return cars;
    }
}

class Car {
    private final String company; // ์ž๋™์ฐจ ํšŒ์‚ฌ
    private final String model; // ์ž๋™์ฐจ ๋ชจ๋ธ

    private final boolean hasParkingTicket;
    private final int parkingMoney;

    public Car(String company, String model, boolean hasParkingTicket, int parkingMoney) {
        this.company = company;
        this.model = model;
        this.hasParkingTicket = hasParkingTicket;
        this.parkingMoney = parkingMoney;
    }

    public String getCompany() {
        return company;
    }

    public String getModel() {
        return model;
    }

    public boolean hasParkingTicket() {
        return hasParkingTicket;
    }

    public int getParkingMoney() {
        return parkingMoney;
    }

    public static boolean hasTicket (Car car) {
        return car.hasParkingTicket;
    }

    public static boolean noTicketHasMoney (Car car) {
        return !car.hasParkingTicket && car.getParkingMoney() > 1000;
    }
}

interface Predicate<T> {
    boolean test(T t);
}

 

์˜ค๋Š˜ ํ•˜๋ฃจ ์ •๋ฆฌโœ๏ธ

ํ•˜๋ฃจ์ข…์ผ ์ž๋ฐ” ๊ฐ•์˜ ๋“ค์œผ๋ฉด์„œ ์‹ค์Šต๋งŒ ํ–ˆ๋˜ ๊ฒƒ ๊ฐ™๋‹ค. Thread ๋ถ€๋ถ„์€ ์–ด๋Š ์ •๋„ ์ดํ•ด๊ฐ€ ๋๋Š”๋ฐ ๋ชจ๋˜ ์ž๋ฐ”์— ์žˆ๋Š” ๋žŒ๋‹ค, ์ŠคํŠธ๋ฆผ์— ๋Œ€ํ•ด์„œ๋Š” ์ถ”๊ฐ€์ ์œผ๋กœ ๊ณต๋ถ€ํ•˜๋ฉด์„œ ์ตํ˜€์•ผ ํ•  ๊ฒƒ ๊ฐ™๋‹ค!

์˜ค๋Š˜ 5์ฃผ์ฐจ ์ˆ™์ œ๊นŒ์ง€ ๋๋‚ด๋Š” ๊ฒƒ์ด ๋ชฉํ‘œ์˜€๋Š”๋ฐ ๊ฐ•์˜๋ฅผ ๋„ˆ๋ฌด ์˜ค๋ž˜ ๋“ค์–ด์„œ ๋‚ด์ผ ์˜ค์ „์œผ๋กœ ๋ฏธ๋ค„์•ผ๊ฒ ๋‹ค.. ์˜ค์ „์—๋Š” ์ˆ™์ œ๋ฅผ ๋๋‚ด๋Š” ๊ฒƒ์„ ๋ชฉํ‘œ๋กœ ํ•˜๊ณ  ์˜คํ›„๋ถ€ํ„ฐ๋Š” ์ถ”๊ฐ€ ๊ณผ์ œ(ํ‚ค์˜ค์Šคํฌ)๋ฅผ ๋„์ „ํ•ด์•ผ๊ฒ ๋‹ค!!

์ด๋ฒˆ ์ผ์ฃผ์ผ๋„ ๊ณต๋ถ€ ์—ด์‹ฌํžˆ ํ•˜๋ฉด์„œ ์ž˜ ๋ฒ„ํ‹ด ๊ฒƒ ๊ฐ™๋‹ค. ๊ณ„์†ํ•ด์„œ ์„ฑ์žฅํ•˜๊ณ  ์žˆ๊ณ  ์ด๋Œ€๋กœ ์ง€์น˜์ง€ ์•Š๊ณ  ๊ณ„์† ํ•ด๋‚˜๊ฐ„๋‹ค๋ฉด ์ข‹์€ ์„ฑ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™๋‹ค. ์ฒซ ๋ฒˆ์งธ ๊ณผ์ œ์ธ ๊ณ„์‚ฐ๊ธฐ ๋งŒ๋“ค๊ธฐ์— ๋Œ€ํ•œ ํŠœํ„ฐ๋‹˜์˜ ํ”ผ๋“œ๋ฐฑ์„ ์˜ค๋Š˜ ํ™•์ธํ–ˆ๋Š”๋ฐ ์ƒ๊ฐ๋ณด๋‹ค ๊ธ์ •์ ์œผ๋กœ ํ”ผ๋“œ๋ฐฑ์„ ๋‚จ๊ฒจ์ฃผ์…”์„œ ํ‚ค์˜ค์Šคํฌ ๊ณผ์ œ์—๋Š” ํ”ผ๋“œ๋ฐฑ์„ ๋ฐ˜์˜ํ•ด์„œ ๊ณผ์ œ๋ฅผ ์™„์„ฑํ•ด์•ผ๊ฒ ๋‹ค!!

์ฃผ๋ง์ด๋ผ๊ณ  ๋Š˜์–ด์ง€์ง€ ๋ง๊ณ  ์ ๋‹นํžˆ ๊ณต๋ถ€ํ•˜๋ฉด์„œ ์‰ฌ์–ด๊ฐ€๋Š” ์‹œ๊ฐ„์„ ๊ฐ€์ ธ์•ผ์ง€~~
์ด๋ฒˆ ์ฃผ๋„ ๊ณ ์ƒํ–ˆ๋‹ค..!!

 

๋‚ด์ผ ๊ณ„ํšโฐ

์˜ค์ „

  • Java ๋ฌธ๋ฒ• ์ข…ํ•ฉ๋ฐ˜_5์ฃผ์ฐจ ์ˆ™์ œ ๋„์ „..!

์˜คํ›„

  • ํ‚ค์˜ค์Šคํฌ ๊ณผ์ œ ์‹œ์ž‘
  • ์ธํ”„๋Ÿฐ ๊ฐ•์˜ ๋“ค์œผ๋ฉด์„œ ๋ถ€์กฑํ•œ ๋ถ€๋ถ„ ์ดํ•ด