프로그래밍/JAVA

쓰레드 wait()과 notify()

Baesj 2021. 9. 29. 20:02

synchronized로 동기화해서 공유 데이터를 보호하는 것 까지는 좋은데, 특정 쓰레드가 객체의 락을 가진 상태로 오랜 시간을 보내지 않도록 하는 것도 중요

 

동기화된 임계 영역의 코드를 수행하다가 작업을 더 이상 진행할 상황이 아니면,

일단 wait()을 호출하여 쓰레드가 락을 반납하고, 기다리게 한다.

나중에 작업을 진행할 수 있는 상황이 되면 notify()를 호출해서,

작업을 중단했던 쓰레드가 다시 락을 얻어 작업을 진행할 수 있게 한다.

 

import java.util.ArrayList;

class BurgerShop {
    String[] burger = {"burger1", "burger2", "burger3"};
    private ArrayList<String> burgerList = new ArrayList<>();

    public synchronized void add(String burger) {
        if (burgerList.size() >= 5) {
            notify();
            return;
        }
        burgerList.add(burger);
        System.out.println("Burger: " + burgerList.toString());
    }

    public boolean remove(String dishName) {
        synchronized (this) {
            while(burgerList.size()==0) {
                String name = Thread.currentThread().getName();
                System.out.println(name + " is waiting");
                try {
                    wait();
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            for (int i = 0; i < burgerList.size(); i++) {
                if(dishName.equals(burgerList.get(i))) {
                    burgerList.remove(i);
                    return true;
                }
            }
        }
        return false;
    }

    public int burgerNum() {
        return burger.length;
    }
}

class Cust implements Runnable {
    private BurgerShop burgerShop;
    private String burger;

    public Cust(BurgerShop burgerShop, String burger) {
        this.burgerShop = burgerShop;
        this.burger = burger;
    }

    public void run() {
        while(true) {
            try {
                Thread.sleep(500);
            }catch (InterruptedException e) {
                e.printStackTrace();
            }
            String name = Thread.currentThread().getName();
            if (eatFood()) {
                System.out.println(name + " ate a" + burger);
            } else {
                System.out.println(name + " failed to eat.");
            }
        }
    }

    boolean eatFood() {
        return burgerShop.remove(burger);
    }
}

class BurgerCook implements Runnable {
    private BurgerShop burgerShop;

    public BurgerCook(BurgerShop burgerShop) {
        this.burgerShop = burgerShop;
    }

    public void run() {
        while(true) {
            int idx = (int)(Math.random()*burgerShop.burgerNum());
            burgerShop.add(burgerShop.burger[idx]);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class ExThreadWaitNotify2 {
    public static void main(String[] args) throws InterruptedException {
        BurgerShop burgerShop = new BurgerShop();

        new Thread(new BurgerCook(burgerShop), "BurgerCook").start();
        new Thread(new Cust(burgerShop, "burger1"), "CUST1").start();
        new Thread(new Cust(burgerShop, "burger2"), "CUST2").start();

        Thread.sleep(5000);
        System.exit(0);
    }
}

 

참고 및 출처

도서 : 자바의 정석

'프로그래밍 > JAVA' 카테고리의 다른 글

(복습) static  (0) 2021.10.04
프로세스와 쓰레드 2  (0) 2021.10.02
쓰레드의 동기화  (0) 2021.09.27
쓰레드 실행제어  (0) 2021.09.26
쓰레드 상태 및 과정  (0) 2021.09.24