Thread...?

์ด์ •๋นˆยท2024๋…„ 4์›” 30์ผ

TIL

๋ชฉ๋ก ๋ณด๊ธฐ
6/8

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

๐Ÿ“Œ Process vs Thread

  • ํ”„๋กœ์„ธ์Šค : ์šด์˜์ฒด์ œ๋กœ ๋ถ€ํ„ฐ ์ž์›์„ ํ• ๋‹น๋ฐ›๋Š” ์ž‘์—…์˜ ๋‹จ์œ„
  • ์“ฐ๋ ˆ๋“œ : ํ”„๋กœ์„ธ์Šค๊ฐ€ ํ• ๋‹น๋ฐ›์€ ์ž์›์„ ์ด์šฉํ•˜๋Š” ์‹คํ–‰์˜ ๋‹จ์œ„

์ฆ‰, ํ•˜๋‚˜ ํ•˜๋‚˜ ํฌ๊ฒŒ ๋ด์„œ ํ”„๋กœ๊ทธ๋žจ๋“ค์„ ํ”„๋กœ์„ธ์Šค๋ผ๊ณ  ํ•˜๊ณ , ๊ทธ ์•ˆ์— ์‹คํ–‰๋˜๋Š” ๊ฒƒ๋“ค์„ ์“ฐ๋ ˆ๋“œ๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“Œ OS๊ฐ€ ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰์„ ์œ„ํ•œ ํ”„๋กœ์„ธ์Šค๋ฅผ ํ• ๋‹น ํ•ด์ค„๋–„ ํ”„๋กœ์„ธ์Šค ์•ˆ์— ํ”„๋กœ๊ทธ๋žจ Code์™€ Data ๊ทธ๋ฆฌ๊ณ  Memory Area(Stack, Heap)์„ ํ•จ๊ป˜ ํ• ๋‹นํ•ด์ค๋‹ˆ๋‹ค.

  • Code๋Š” Java main ๊ณผ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ๋งํ•ฉ๋‹ˆ๋‹ค.

  • Data๋Š” ํ”„๋กœ๊ทธ๋žจ์ด ์‹คํ–‰ ์ค‘ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋Š” ์ €์žฅ๊ณต๊ฐ„์„ ๋งํ•ฉ๋‹ˆ๋‹ค.
    - ์ „์—ญ, ์ •์ , ๋ฐฐ์—ด ๋“ฑ ์ดˆ๊ธฐํ™”๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋Š” ๊ณต๊ฐ„

  • Memory Area
    - Stack : ์ง€์—ญ๋ณ€์ˆ˜, ๋งค๊ฐœ๋ณ€์ˆ˜ ๋ฆฌํ„ด ๋ณ€์ˆ˜๋ฅผ ์ €์žฅํ•˜๋Š” ๊ณต๊ฐ„
    - Heap : ํ”„๋กœ๊ทธ๋žจ์ด ๋™์ ์œผ๋กœ ํ•„์š”ํ•œ ๋ณ€์ˆ˜๋ฅผ ์ €์žฅํ•˜๋Š” ๊ณต๊ฐ„(new(), mallok())

Thread

: ์“ฐ๋ ˆ๋“œ๋Š” ํ”„๋กœ์„ธ์Šค ๋‚ด์—์„œ ์ผํ•˜๋Š” ์ผ๊พผ์œผ๋กœ, ์ฝ”๋“œ ์‹คํ–‰์˜ ํ๋ฆ„์ด๋ผ๊ณ  ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์“ฐ๋ ˆ๋“œ์˜ ์ž์›
    - ํ”„๋กœ์„ธ์Šค ์•ˆ์—๋Š” ์—ฌ๋Ÿฌ ์“ฐ๋ ˆ๋“œ๋“ค์ด ์žˆ๊ณ , ์“ฐ๋ ˆ๋“œ๋“ค์€ ์‹คํ–‰์„ ์œ„ํ•œ ํ”„๋กœ์„ธ์Šค ๋‚ด ์ฃผ์†Œ๊ณต๊ฐ„์ด๋‚˜ Heap์„ ๊ณต์œ  ๋ฐ›์Šต๋‹ˆ๋‹ค.
    - ์ถ”๊ฐ€๋กœ, ์“ฐ๋ ˆ๋“œ๋“ค์€ ๊ฐ๊ฐ ๋ช…๋ น์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ์ž์‹ ๋งŒ์˜ ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„๋„ ํ• ๋‹น ๋ฐ›์Šต๋‹ˆ๋‹ค.

๐Ÿ“Œ ์ผ๋ฐ˜ ์“ฐ๋ ˆ๋“œ์™€ ๋™์ผํ•˜๋ฉฐ JVM ํ”„๋กœ์„ธ์Šค ์•ˆ์—์„œ ์‹คํ–‰๋˜๋Š” ์“ฐ๋ ˆ๋“œ๋ฅผ Java Thread๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

  • Java๋ฅผ ์‹คํ–‰ํ•˜๋ฉด JVM ํ”„๋กœ์„ธ์Šค ์œ„์—์„œ ์‹คํ–‰์ด ๋ฉ๋‹ˆ๋‹ค.

๋ฉ€ํ‹ฐ ์“ฐ๋ ˆ๋“œ(โ† โ†’ ์‹ฑ๊ธ€ ์“ฐ๋ ˆ๋“œ)

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

  • ๋ฉ”์ธ ์“ฐ๋ ˆ๋“œ๋Š” ํ•„์š”์— ๋”ฐ๋ผ์„œ ์ž‘์—… ์“ฐ๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•ด์„œ ๋ณ‘๋ ฌ๋กœ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ฆ‰, Multi Thread ๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.
  1. Single Thread

๐Ÿ“Œ ํ”„๋กœ์„ธ์Šค ์•ˆ์—์„œ ํ•˜๋‚˜์˜ ์“ฐ๋ ˆ๋“œ๋งŒ ์‹คํ–‰๋˜๋Š” ๊ฒƒ์„ ๋งํ•ฉ๋‹ˆ๋‹ค.

  • Java์˜ ๊ฒฝ์šฐ main() ๋ฉ”์„œ๋“œ๋งŒ ์‹คํ–‰์‹œ์ผฐ์„ ๋•Œ Single Thread๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.
  • ๊ทธ๋ž˜์„œ, ํ”„๋กœ๊ทธ๋žจ์ด ์ข…๋ฃŒ๊ฐ€ ๋  ๊ฒฝ์šฐ Main Thread๊ฐ€ ์ข…๋ฃŒ๋˜๋Š” ๊ฒƒ์ด๊ณ , JVM๋„ ๊ฐ™์ด ์ข…๋ฃŒ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.
    public class Main {
        public static void main(String[] args) {
            Runnable task = () -> {
            	  System.out.print("2๋ฒˆ -> " + Thread.currentThread().getName());
                for (int i = 0; i < 100; i++) {
                    System.out.print("$");
                }
            };
    
    				System.out.print("1๋ฒˆ -> " + Thread.currentThread().getName());
            Thread thread1 = new Thread(task);
            thread1.setName("thread1");
    
            thread1.start();
        }
    }

์œ„์˜ ์ฝ”๋“œ๋ฅผ ๋ถ„์„ํ•˜๋ฉด, 1๋ฒˆ์˜ main ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋จผ์ € ์‹คํ–‰๋˜๊ณ , ๊ทธ์— ๋”ฐ๋ผ Thread1 ์ด ์‹คํ–‰๋˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  1. Multi Thread

๐Ÿ“Œ ํ”„๋กœ์„ธ์Šค ์•ˆ์—์„œ ์—ฌ๋Ÿฌ๊ฐœ์˜ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์‹คํ–‰๋˜๋Š” ๊ฒƒ์„ ๋งํ•ฉ๋‹ˆ๋‹ค.

  • ํ•˜๋‚˜์˜ ํ”„๋กœ์„ธ์Šค๋Š” ์—ฌ๋Ÿฌ๊ฐœ์˜ ์‹คํ–‰๋‹จ์œ„(์“ฐ๋ ˆ๋“œ)๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์œผ๋ฉฐ ์ด ์“ฐ๋ ˆ๋“œ๋“ค์€ ํ”„๋กœ์„ธ์Šค์˜ ์ž์›์„ ๊ณต์œ ํ•ฉ๋‹ˆ๋‹ค.
  • Java๋Š” main Thread์™ธ์— ๋‹ค๋ฅธ ์ž‘์—…์„ ์ƒ์„ฑํ•˜์—ฌ ๋™์‹œ ๋‹ค๋ฐœ์ ์ธ ์‹คํ–‰ ํ๋ฆ„์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • Multi Thread ์žฅ์ 
    - ๋™์‹œ ๋‹ค๋ฐœ์ ์ธ ์‹คํ–‰์œผ๋กœ ์ฒ˜๋ฆฌ ์†๋„๊ฐ€ ๋นจ๋ผ์ง‘๋‹ˆ๋‹ค.
    - ์Šคํƒ์„ ์ œ์™ธํ•œ ๋ชจ๋“  ์˜์—ญ์—์„œ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ณต์œ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ž์›์„ ๋ณด๋‹ค ํšจ์œจ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋‹จ์ 
    - ๋™๊ธฐํ™” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    - ํ”„๋กœ์„ธ์Šค์˜ ์ž์›์„ ๊ณต์œ  ํ•˜๋ฉด์„œ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ถฉ๋Œํ•˜์—ฌ, Dead Lock ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (์„œ๋กœ ์ ์œ ํ•˜๊ณ  ์žˆ๋Š” Resource๋ฅผ ๋‚ด๋†“์„ ๋•Œ ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๋Š” ์‹œ๊ฐ„์ด ๋ฌดํ•œ๋Œ€๋กœ ๋Š˜์–ด๋‚˜ ๊ต์ฐฉ์ƒํƒœ๊ฐ€ ์ง€์†๋˜๋Š” ๊ฒƒ์„ Dead Lock ์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.)
    - ์ด๋Ÿฌํ•œ ์ถฉ๋Œ์€, ์šฐ๋ฆฌ๊ฐ€ ํ”„๋กœ์„ธ์Šค์˜ ์‹คํ–‰์‹œ๊ฐ„์„ ์˜ˆ์ธกํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌธ์ œ์ค‘ ํ•˜๋‚˜ ์ž…๋‹ˆ๋‹ค. ์ฆ‰, OS์˜ ์ƒํ™ฉ์— ๋”ฐ๋ผ ๊ฐ€๋ณ€์ ์œผ๋กœ ๋ณ€ํ•˜๊ฒŒ ๋จ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    Runnable task = () -> {
                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(task);
            thread1.setName("thread1");
            Thread thread2 = new Thread(task2);
            thread2.setName("thread2");
    
            thread1.start();
            thread2.start();
        }
  • ์‹ค์ œ ๊ตฌํ˜„
    public class Main{
    	public static void main(String args[]){
    	  // ์ด๋Ÿฐ์‹์œผ๋กœ Thread๋ฅผ extendsํ•œ ํด๋ž˜์Šค๋ฅผ ์ธ์Šคํ„ด์Šคํ™” ์‹œ์ผœ์„œ ๋‚ด๋ถ€์˜ 
    	  // `run()`์„ ๊ตฌํ˜„ํ•œ ๋™์ž‘์„ ์‹คํ–‰ ์‹œํ‚ต๋‹ˆ๋‹ค.
    		TestThread thread = new TestThread();
    		thread.start();
    	}
    }
    public class Main{
    	public static void main(String args[]){
    	  // ์ด๋Ÿฐ์‹์œผ๋กœ Runnable๋ฅผ implementsํ•œ ํด๋ž˜์Šค๋ฅผ ์ธ์Šคํ„ด์Šคํ™” ์‹œ์ผœ์„œ ๋‚ด๋ถ€์˜ 
    	  // `run()`์„ ๊ตฌํ˜„ํ•œ ๋™์ž‘์„ ์‹คํ–‰ ์‹œํ‚ต๋‹ˆ๋‹ค.
    		Runnable thread = new TestRunnable();
    		thread.start();
    	}
    }
    public class Main{
    	public static void main(String args[]){
    	  // ์ด๋Ÿฐ์‹์œผ๋กœ Runnable๋ฅผ implementsํ•œ ํด๋ž˜์Šค๋ฅผ ์ธ์Šคํ„ด์Šคํ™” ์‹œ์ผœ์„œ ๋‚ด๋ถ€์˜ 
    	  // `run()`์„ ๊ตฌํ˜„ํ•œ ๋™์ž‘์„ ์‹คํ–‰ ์‹œํ‚ต๋‹ˆ๋‹ค.
    		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);
    		}
    	}
    }
    ๋งˆ์ง€๋ง‰์˜ lambda ์˜ ๋ฐฉ์‹์œผ๋กœ ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด๋Ÿฌํ•œ ๋ฐฉ์‹์— ๋Œ€ํ•ด์„œ ์ต์ˆ™ํ•ด์งˆ ํ•„์š”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ, task๋ฅผ ๋™์‹œ์— ์—ฌ๋Ÿฌ๊ฐœ์˜ Thread์— ์‹คํ•ด์„ ํ•˜๊ฒŒ ๋˜๋ฉด ์ถœ๋ ฅ ๊ฐ’์ด ์„ž์—ฌ์„œ ๋‚˜์˜ค๋Š” ๊ฒƒ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Demon & User Thread

Demon Thread

๐Ÿ“Œ ๋ณด์ด์ง€ ์•Š๋Š”๊ณณ(background)์—์„œ ์‹คํ•ด์˜ค๋””๋Š” ๋‚ฎ์€ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ฐ€์ง„ ์“ฐ๋ ˆ๋“œ๋ฅผ ๋งํ•ฉ๋‹ˆ๋‹ค.

  • ๋ณด์กฐ์ ์ธ ์—ญํ• ์„ ๋‹ด๋‹นํ•˜๋ฉฐ ๋Œ€ํ‘œ์ ์ธ ๋ฐ๋ชฌ ์“ฐ๋ ˆ๋“œ๋กœ๋Š” ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ์„ ์ •๋ฆฌํ•ด์ฃผ๋Š” GBC(Garbage Collector)๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์„ค์ • ๋ฐฉ๋ฒ•
    public class Main {
        public static void main(String[] args) {
            Runnable demon = () -> {
                for (int i = 0; i < 1000000; i++) {
                    System.out.println("demon");
                }
            };
    
            // ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ์— ๋น„ํ•ด ๋ฆฌ์†Œ์Šค๋ฅผ ์ ๊ฒŒ ํ• ๋‹น ๋ฐ›๊ธฐ ๋•Œ๋ฌธ์— ์ƒ๋Œ€์ ์œผ๋กœ ๋А๋ฆฌ๊ฒŒ ์‹คํ–‰์ด ๋ฉ๋‹ˆ๋‹ค.
            Thread thread = new Thread(demon);
            thread.setDaemon(true); // true๋กœ ์„ค์ •์‹œ ๋ฐ๋ชฌ์Šค๋ ˆ๋“œ๋กœ ์‹คํ–‰๋จ
    
            thread.start();
    
            for (int i = 0; i < 100; i++) {
                System.out.println("task");
            }
        }
    }

์ด๋Ÿฐ, Demon Thread๋Š” ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋‹ค ๋๋‚  ๋•Œ ๊นŒ์ง€ ๊ธฐ๋‹ค๋ ค์ง€๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์–ด๋А์ •๋„ ์‹œ๊ฐ„์ด ์ง€๋‚˜๋ฉด ๋๋‚˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ , ์ด๋ ‡๊ฒŒ Demon Thread๋ฅผ ์ œ์™ธํ•œ ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“  ์“ฐ๋ ˆ๋“œ๋“ค์„ User Thread ๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

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

๐Ÿ“Œ ์“ฐ๋ ˆ๋“œ ์ž‘์—…์˜ ์ค‘์š”๋„์— ๋”ฐ๋ผ์„œ ์“ฐ๋ ˆ๋“œ์˜ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๋ถ€์—ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์œ„์˜ ์šฐ์„ ์ˆœ์œ„๋ฅผ ์ฃผ์–ด์„œ, ์ž‘์—… ์‹œ๊ฐ„์„ ํ• ๋‹นํ•ด ๊ธ‰ํ•œ ๊ฒƒ์„ ๋จผ์ € ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ์‹์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

- ์šฐ์„ ์ˆœ์œ„๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด 3๊ฐ€์ง€๋กœ ๋‚˜๋‰ฉ๋‹ˆ๋‹ค.
    - MAX_PRIORITY = 10
    - MIN_PRIORITY = 1
    - NROM_PRIORITY = 5
        - ๊ธฐ๋ณธ ๊ฐ’์ด ๋ณดํ†ต ์šฐ์„ ์ˆœ์œ„ ์ž…๋‹ˆ๋‹ค.
    - ์ด ์šฐ์„ ์ˆœ์œ„์˜ ๋ฒ”์œ„๋Š” OS๊ฐ€ ์•„๋‹ˆ๋ผ JVM์—์„œ ์„ค์ •ํ•œ ์šฐ์„ ์ˆœ์œ„์ž…๋‹ˆ๋‹ค.
    Thread thread1 = new Thread();
    thread1.setPriority(8);
  • ์“ฐ๋ ˆ๋“œ ๊ทธ๋ฃน์€ ๋ง ๊ทธ๋Œ€๋กœ, ๋ฉ”์ธ ์“ฐ๋ ˆ๋“œ ์•ˆ์˜ ๋‹ค์–‘ํ•œ ์“ฐ๋ ˆ๋“œ๋ฅผ ํŠน์ง•๋งˆ๋‹ค ๋ฌถ์–ด์„œ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์ƒ๊ธฐ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
  • ๋ชจ๋“  ์“ฐ๋ ˆ๋“œ๋Š” ๋ฐ˜๋“œ์‹œ ํ•˜๋‚˜์˜ ๊ทธ๋ฃน์— ํฌํ•จ๋˜์–ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
    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();
    
        }
    }

์“ฐ๋ ˆ๋“œ ์ƒํƒœ์™€ ์ œ์–ด

๐Ÿ“Œ ์šฐ๋ฆฌ๋Š” ๋™์˜์ƒ์„ ๋ณด๊ฑฐ๋‚˜ ์Œ์•…์„ ๋“ฃ๊ณ  ์žˆ์„ ๋•Œ ์ผ์‹œ์ •์ง€ ํ›„์— ๋‹ค์‹œ ๋ณด๊ฑฐ๋‚˜ ๋“ฃ๊ธฐ๋„ ํ•˜๊ณ  ์ค‘๊ฐ„์— ์ข…๋ฃŒ ์‹œํ‚ค๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค. ์“ฐ๋ ˆ๋“œ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ƒํƒœ๊ฐ€ ์กด์žฌํ•˜๊ณ  ์ด๋ฅผ ์ œ์–ด๋ฅผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์“ฐ๋ ˆ๋“œ ์ƒํƒœ

  • ์ด์ฒ˜๋Ÿผ ์“ฐ๋ ˆ๋“œ๋Š” ์‹คํ–‰๊ณผ ๋Œ€๊ธฐ๋ฅผ ๋ฐ˜๋ณตํ•˜๋ฉฐ run() ๋ฉ”์„œ๋“œ๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  • ๋ฉ”์„œ๋“œ๊ฐ€ ์ข…๋ฃŒ๋˜๋ฉด run() method๋„ ๋˜ํ•œ ์ข…๋ฃŒ๋ฉ๋‹ˆ๋‹ค.

  • ์ผ์‹œ์ •์ง€ ์ƒํƒœ์—์„œ๋Š” ์“ฐ๋ ˆ๋“œ๊ฐ€ ์‹คํ–‰์„ ํ•  ์ˆ˜ ์—†๋Š” ์ƒํƒœ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

๐Ÿ“Œ ์•„๋ž˜๋Š” ์“ฐ๋ ˆ๋“œ์˜ ์ƒํƒœ๋ฅผ ์ •๋ฆฌํ•œ ํ‘œ์ž…๋‹ˆ๋‹ค.

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

์“ฐ๋ ˆ๋“œ ์ œ์–ด

Sleep(), interupt()

  1. sleep() : ํ˜„์žฌ ์“ฐ๋ ˆ๋“œ๋ฅผ ์ง€์ •๋œ ์‹œ๊ฐ„๋™์•ˆ ๋ฉˆ์ถ”๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. - TIMED-WAITING

    public class Main {
        public static void main(String[] args) {
            Runnable task = () -> {
                try {
    		            // (1) ์˜ˆ์™ธ์ฒ˜๋ฆฌ ํ•„์ˆ˜! 
    		            // - interrunpt() ๋ฅผ ๋งŒ๋‚˜๋ฉด ๋‹ค์‹œ ์‹คํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์—
    		            // - interruptedException์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.
    		            // (2) ํŠน์ • ์“ฐ๋ ˆ๋“œ ์ง€๋ชฉ ๋ถˆ๊ฐ€
                    Thread.sleep(2000); // TIMED_WAITING
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("task : " + Thread.currentThread().getName());
            };
    
            Thread thread = new Thread(task, "Thread");
            thread.start();
    
            try {
    		        // 1์ดˆ๊ฐ€ ์ง€๋‚˜๊ณ  ๋‚˜๋ฉด runnable ์ƒํƒœ๋กœ ๋ณ€ํ•˜์—ฌ ๋‹ค์‹œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.
    		        // ํŠน์ • ์Šค๋ ˆ๋“œ๋ฅผ ์ง€๋ชฉํ•ด์„œ ๋ฉˆ์ถ”๊ฒŒ ํ•˜๋Š” ๊ฒƒ์€ ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
    		        //
                thread.sleep(1000); // static method์ด๊ธฐ ๋•Œ๋ฌธ์— main thread์™€ ๊ฐ™์€ ๋™์ž‘์„ ํ•ฉ๋‹ˆ๋‹ค.
                System.out.println("sleep(1000) : " + Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

Thread.sleep() ๋ฉ”์„œ๋“œ ์ž์ฒด๊ฐ€ static์œผ๋กœ ์„ ์–ธ์ด ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ํŠน์ • ๋ถ€๋ถ„์— ๋Œ€ํ•ด์„œ sleep์„ ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ์“ฐ๋ ˆ๋“œ ์ž์ฒด์— ์‹œ๊ฐ„์„ ์ผ์ • ์ž…๋ ฅํ•œ ์‹œ๊ฐ„๋™์•ˆ ๋ฉˆ์ถ”๊ฒŒ ํ•˜๋Š” ๊ฒƒ์ž„์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ try-catch ๋กœ ๊ฐ์‹ธ์ค€ ์ด์œ ๋Š” ํ•ด๋‹น sleep() ๋ฉ”์„œ๋“œ๋Š” throws InterruptedException์„ ๋ฐ˜ํ™˜ํ•˜์—ฌ ์œ„ํ—˜ํ•œ ๋ฉ”์„œ๋“œ์ž„์„ ์•Œ๋ ค์ฃผ๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ์‹ธ์ฃผ๊ณ  ์žˆ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

  1. Interrupt() : ์ผ์‹œ์ •์ง€ ์ƒํƒœ์ธ ์“ฐ๋ ˆ๋“œ๋ฅผ ์‹คํ–‰๋Œ€๊ธฐ ์ƒํƒœ๋กœ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

    public class Main {
        public static void main(String[] args) {
            Runnable task = () -> {
                try {
                    Thread.sleep(1000);
                    System.out.println(Thread.currentThread().getName());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("task : " + Thread.currentThread().getName());
            };
    
            Thread thread = new Thread(task, "Thread");
            thread.start(); // NEW -> Runnable๋กœ ๊ฐ€์„œ ์‹คํ–‰์ด ๋ฉ๋‹ˆ๋‹ค.
    
            thread.interrupt(); // ์Šค๋ ˆ๋“œ๋ฅผ ์‹คํ–‰๋Œ€๊ธฐ ์ƒํƒœ๋ฅผ ๋ฐฉํ•ดํ•˜๊ณ  catch๋ฌธ์œผ๋กœ ๋น ์ง€๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
    
            System.out.println("thread.isInterrupted() = " + thread.isInterrupted());
    
        }
    }
    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("task : " + Thread.currentThread().getName());
            };
    
            Thread thread = new Thread(task, "Thread");
            thread.start();
    
            thread.interrupt();
    
            System.out.println("thread.isInterrupted() = " + thread.isInterrupted());
            
        }
    }
  2. Join()

๐Ÿ“Œ ์ •ํ•ด์ง„ ์‹œ๊ฐ„ ๋™์•ˆ ์ง€์ •ํ•œ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ž‘์—…ํ•˜๋Š” ๊ฒƒ์„ ๊ธฐ๋‹ค๋ฆฝ๋‹ˆ๋‹ค.

  • ์‹œ๊ฐ„์„ ์ง€์ •ํ•˜์ง€ ์•Š์•˜์„ ๋•Œ๋Š” ์ง€์ •ํ•œ ์“ฐ๋ ˆ๋“œ์˜ ์ž‘์—…์ด ๋๋‚  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฝ๋‹ˆ๋‹ค.
  • join() ์‚ฌ์šฉ๋ฐฉ๋ฒ•
    Thread thread = new Thread(task, "thread");
    
    thread.start();
    
    try {
        thread.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    • Thread.sleep(ms); ms(๋ฐ€๋ฆฌ์ดˆ) ๋‹จ์œ„๋กœ ์„ค์ •๋ฉ๋‹ˆ๋‹ค.

    • ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

      • **interrupt() ๋ฅผ ๋งŒ๋‚˜๋ฉด ๊ธฐ๋‹ค๋ฆฌ๋Š” ๊ฒƒ์„ ๋ฉˆ์ถ”๊ธฐ ๋•Œ๋ฌธ์— InterruptedException์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.**
    • ์‹œ๊ฐ„์„ ๋”ฐ๋กœ ์ง€์ •ํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— thread๊ฐ€ ์ž‘์—…์ด ๋๋‚  ๋•Œ๊นŒ์ง€ main ์“ฐ๋ ˆ๋“œ๋Š” ๊ธฐ๋‹ค๋ฆฌ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

      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");
      
              thread.start();
      
              long start = System.currentTimeMillis();
      
              try {
                  thread.join();
      
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
      
              // thread ์˜ ์†Œ์š”์‹œ๊ฐ„์ธ 5000ms ๋™์•ˆ main ์“ฐ๋ ˆ๋“œ๊ฐ€ ๊ธฐ๋‹ค๋ ธ๊ธฐ ๋•Œ๋ฌธ์— 5000์ด์ƒ์ด ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค.
              System.out.println("์†Œ์š”์‹œ๊ฐ„ = " + (System.currentTimeMillis() - start));
          }
      }
  • yield()

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

  • yield() ์‚ฌ์šฉ๋ฐฉ๋ฒ•

    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(); // thread1์˜ resource๊ฐ€ 5์ดˆ๋’ค์— thread2๋กœ ์–‘๋„๋ฉ๋‹ˆ๋‹ค.
                }
            };
    
            Thread thread1 = new Thread(task, "thread1");
            Thread thread2 = new Thread(task, "thread2");
    
            thread1.start();
            thread2.start();
    
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            thread1.interrupt(); // ์‹คํ–‰๋Œ€๊ธฐ ์ƒํƒœ๋กœ ๋งŒ๋“ ๋‹ค.
    
        }
    }
    • 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");
            Thread thread2 = new Thread(task, "thread2");
    
            thread1.start();
            thread2.start();
    
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            thread1.interrupt();
    
        }
    }
  1. synchronized()

๐Ÿ“Œ ๋ฉ€ํ‹ฐ ์“ฐ๋ ˆ๋“œ์˜ ๊ฒฝ์šฐ ์—ฌ๋Ÿฌ ์“ฐ๋ ˆ๋“œ๊ฐ€ ํ•œ ํ”„๋กœ์„ธ์Šค์˜ ์ž์›์„ ๊ณต์œ ํ•ด์„œ ์ž‘์—…ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์„œ๋กœ์—๊ฒŒ ์˜ํ–ฅ์„ ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋กœ ์ธํ•ด์„œ ์žฅ์• ๋‚˜ ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ด๋Ÿฌํ•œ ์ผ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด(์ž์›์„ ๊ณต์œ ํ•˜๋‹ค๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ๋Š” ์˜ค๋ฅ˜) ํ•œ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ง„ํ–‰์ค‘์ธ ์ž‘์—…์„ ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์นจ๋ฒ”ํ•˜์ง€ ๋ชปํ•˜๋„๋ก ๋ง‰๋Š” ๊ฒƒ์„ Thread Synchronized ๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.
  • ๋™๊ธฐํ™”๋ฅผ ํ•˜๋ ค๋ฉด ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ์˜ ์นจ๋ฒ”์„ ๋ง‰์•„์•ผ ํ•˜๋Š” ์ฝ”๋“œ๋“ค์„ ์ž„๊ณ„ ์˜์—ญ ์œผ๋กœ ์„ค์ •ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.
  • synchronized ๋ฅผ ์‚ฌ์šฉํ•œ ๋™๊ธฐํ™”
    - ์‹คํ–‰ํ•  ๋ฉ”์„œ๋“œ ๋˜๋Š” ์‹คํ–‰ํ•  ์ฝ”๋“œ ๋ฌถ์Œ ์•ž์— synchronized๋ฅผ ๋ถ™์—ฌ์„œ ์ž„๊ณ„ ์˜์—ญ์„ ์ง€์ •ํ•˜์—ฌ ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ์˜ ์นจ๋ฒ”์„ ๋ง‰์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.(์นจ๋ฒ”์„ ๋ง‰๋‹ค = Lock์„ ๊ฑฐ๋Š” ๊ฒƒ ์ž…๋‹ˆ๋‹ค.)
    - ์ž„๊ณ„ ์˜์—ญ ์ง€์ •
    - ๋ฉ”์„œ๋“œ ์ „์ฒด๋ฅผ ์ž„๊ณ„ ์˜์—ญ์œผ๋กœ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.
                public synchronized void asyncSum() {
                	  ...์นจ๋ฒ”์„ ๋ง‰์•„์•ผํ•˜๋Š” ์ฝ”๋“œ...
                }
  • ํŠน์ • ์˜์—ญ์„ ์ž„๊ณ„ ์˜์—ญ์œผ๋กœ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.
                synchronized(ํ•ด๋‹น ๊ฐ์ฒด์˜ ์ฐธ์กฐ๋ณ€์ˆ˜) {
                		...์นจ๋ฒ”์„ ๋ง‰์•„์•ผํ•˜๋Š” ์ฝ”๋“œ...
                }
  • synchronized ์‚ฌ์šฉ ๋ฐฉ๋ฒ•
    - synchronzied ์—†์„ ๋•Œ
          

๋‚จ์€ ์‚ฌ๊ณผ์˜ ์ˆ˜๊ฐ€ ๋’ค์ฃฝ๋ฐ•์ฃฝ ์ถœ๋ ฅ๋  ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์—†๋Š” ์‚ฌ๊ณผ๋ฅผ ๋จน๋Š” ๊ฒฝ์šฐ๋„ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

            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());
                        }
            
                    };
            
                    for (int i = 0; i < 3; i++) {
                        new Thread(task).start();
                    }
                }
            }
            
            class AppleStore {
                private int storedApple = 10;
            
                public int getStoredApple() {
                    return storedApple;
                }
            
                public void eatApple() {
                    if (storedApple > 0) {
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        storedApple -= 1;
                    }
                }
            }
            ```
            
            - `synchronized` ์žˆ์„ ๋•Œ
            
            ```java
            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());
                        }
            
                    };
            
                    for (int i = 0; i < 3; i++) {
                        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()

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

  • ๊ทธ๋Ÿผ ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋ฝ์„ ์–ป์–ด ํ•ด๋‹น ๊ฐ์ฒด์— ๋Œ€ํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜๊ณ , ํ›„์— ์ž‘์—…์„ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ์ƒํ™ฉ์ด ๋˜๋ฉด ํ˜ธ์ถœํ•ด ๋‹ค์‹œ Lock์„ ์–ป์–ด ์ง„ํ–‰ ๊ฐ€๋Šฅ
  1. wait() : ์‹คํ–‰ ์ค‘์ด๋˜ ์“ฐ๋ ˆ๋“œ๋Š” ํ•ด๋‹น ๊ฐ์ฒด์˜ waiting pool์—์„œ ํ†ต์ง€๋ฅผ ๊ธฐ๋‹ค๋ฆฝ๋‹ˆ๋‹ค.
  2. notify() : ํ•ด๋‹น ๊ฐ์ฒด์˜ waiting pool ์— ์žˆ๋Š” ๋ชจ๋“  ์“ฐ๋ ˆ๋“œ ์ค‘์—์„œ ์ž„์˜์˜ ์“ฐ๋ ˆ๋“œ๋งŒ ํ†ต์ง€๋ฅผ ๋ฐ›์Šต๋‹ˆ๋‹ค.
        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๊นŒ์ง€ ๋žœ๋คํ•œ ์ˆซ์ž ์ถœ๋ ฅ
                            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);
                            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์„ ํ’€๊ณ , ๋‚˜์ค‘์— ๋‹ค์‹œ ์–ป์–ด ์ž„๊ณ„์˜์—ญ์œผ๋กœ ์ง„์ž…์ด ๊ฐ€๋Šฅ
            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();
                    }
                }
            }

์ด๋•Œ, ํ•ด๋‹น ๋ฝ์„ ์‚ฌ์šฉํ•˜๋ฉด, ๊ฐ™์€ ์Šค๋ ˆ๋“œ๊ฐ€ ๊ฐ™์€ ๋ฝ์„ ๊ฐ€์ง€๊ณ  ์žˆ์–ด๋„ ์œ ์ง€ํ•˜๋ฉฐ ๊ณ„์† ์‹คํ–‰ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

  • ReentrantReadWriteLock
    - ์ฝ๊ธฐ๋ฅผ ์œ„ํ•œ Lock๊ณผ ์“ฐ๊ธฐ๋ฅผ ์œ„ํ•œ Lock์„ ๋”ฐ๋กœ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
    - ์ผ๊ธฐ์—๋Š” ๊ณต์œ ์ ์ด๊ณ , ์“ฐ๊ธฐ์—๋Š” ๋ฒ ํƒ€์ ์ธ Lock์ž…๋‹ˆ๋‹ค.
    - ์ฝ๊ธฐ lock์ด ๊ฑธ๋ ค์žˆ์œผ๋ฉด ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๋“ค๋„ ์ฝ๊ธฐ Lock์„ ์ค‘๋ณต์œผ๋กœ ๊ฑธ๊ณ  ์ฝ๊ธฐ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.(read-only and ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ ๋ฐฉ์ง€)
    - StampedLock : ์‚ฌ์šฉํ• ๋•Œ๋งŒ ๋ฝ์„ ๊ฑด๋‹ค!

๐Ÿ“Œ wait() & notify()์˜ ๋ฌธ์ œ์ ์ธ waiting pool ๋‚ด ์“ฐ๋ ˆ๋“œ๋ฅผ ๊ตฌ๋ถ„ํ•˜์ง€ ๋ชปํ•œ๋‹ค๋Š” ๊ฒƒ์„ ํ•ด๊ฒฐํ•œ ๊ฒƒ์ด Condition์ž…๋‹ˆ๋‹ค.

[์ถ”๊ฐ€ ์„ค๋ช…]

wait()๊ณผ notify()๋Š” ๊ฐ์ฒด์— ๋Œ€ํ•œ ๋ชจ๋‹ˆํ„ฐ๋ง ๋ฝ(lock)์„ ์ด์šฉํ•˜์—ฌ ์Šค๋ ˆ๋“œ๋ฅผ ๋Œ€๊ธฐ์‹œํ‚ค๊ณ  ๊นจ์›๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ wait()๊ณผ notify()๋Š” waiting pool ๋‚ด์— ๋Œ€๊ธฐ ์ค‘์ธ ์Šค๋ ˆ๋“œ๋ฅผ ๊ตฌ๋ถ„ํ•˜์ง€ ๋ชปํ•˜๋ฏ€๋กœ, ํŠน์ • ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ์Šค๋ ˆ๋“œ๋งŒ ๊นจ์šฐ๊ธฐ๊ฐ€ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด JDK 5์—์„œ๋Š” java.util.concurrent.locks ํŒจํ‚ค์ง€์—์„œ Condition ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. Condition์€ waiting pool ๋‚ด์˜ ์Šค๋ ˆ๋“œ๋ฅผ ๋ถ„๋ฆฌํ•˜์—ฌ ํŠน์ • ์กฐ๊ฑด์ด ๋งŒ์กฑ๋  ๋•Œ๋งŒ ๊นจ์šฐ๋„๋ก ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, 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(); // ์ž„๊ณ„์˜์—ญ ๋
        			}
        		}
        	}
profile
๋ฐฑ์—”๋“œ ํ™”์ดํŒ… :)

0๊ฐœ์˜ ๋Œ“๊ธ€