/ JAVAJUNGSUK

Ch13-34~36. wait(), notify()

자바의 정석 기초편

0. 목차



Chapter13. 쓰레드

Ch13 - 34. wait()과 notify()

Ch13 - 35. wait()과 notify() 예제1

Ch13 - 36. wait()과 notify() 예제2



Ch13 - 34. wait()과 notify()


▶ synchronized의 최대 단점

▷ 한 번에 한 쓰레드만 사용할 수 있으니 동기화가 비효율적
▷ 동기화의 효율을 높이기 위해 만든 게 wait()과 notify()


▶ wait()과 notify()

▷ Object 클래스에 정의되어 있으며, 동기화 블록 내에서만 사용 가능


▶ wait()

▷ 기다리기
▷ 객체의 lock을 풀고 쓰레드를 해당 객체의 waiting pool에 넣음


▶ notify(), notifyAll()

▷ 알려주기
▷ notify()
  • waiting pool에서 대기 중인 쓰레드 중 하나를 깨움
▷ notifyAll()
  • waiting pool에서 대기 중인 모든 쓰레드를 깨움
  • 다 깨워도 나가는 건 하나만



Ch13 - 35. wait()과 notify() 예제1


▶ 동기화X : Customer, Cook, Table

▷ Customer : dish(음식)를 먹음
▷ Cook : dish(음식)를 줌
▷ Table : dish(음식)를 위해 판 깔아 주는 것, dish가 있다 없다 함




Ch13 - 36. wait()과 notify() 예제2


▶ synchronized 동기화O : Customer, Cook, Table

▷ 에러는 안남, 하지만 먹지를 못함



▶ synchronized, wait(), notify() 동기화O : Customer, Cook, Table

▷ Customer
import java.util.ArrayList;

class Customer2 implements Runnable {
	private Table2  table;
	private String food;

	Customer2(Table2 table, String food) {
		this.table = table;  
		this.food  = food;
	}

	public void run() {
		while(true) {
			try { Thread.sleep(100);} catch(InterruptedException e) {}
			String name = Thread.currentThread().getName();
			
			table.remove(food);
			System.out.println(name + " ate a " + food);
		} // while
	}
}
▷ Cook
class Cook2 implements Runnable {
	private Table2 table;
	
	Cook2(Table2 table) { this.table = table; }

	public void run() {
		while(true) {
			int idx = (int)(Math.random()*table.dishNum());
			table.add(table.dishNames[idx]);
			try { Thread.sleep(10);} catch(InterruptedException e) {}
		} // while
	}
}
▷ Table
class Table2 {
	String[] dishNames = { "donut","donut","burger" }; // donut의 확률을 높인다.
	final int MAX_FOOD = 6;
	private ArrayList<String> dishes = new ArrayList<>();

	public synchronized void add(String dish) {
		while(dishes.size() >= MAX_FOOD) {
				String name = Thread.currentThread().getName();
				System.out.println(name+" is waiting.");
				try {
					wait(); // COOK쓰레드를 기다리게 한다.
					Thread.sleep(500);
				} catch(InterruptedException e) {}	
		}
		dishes.add(dish);
		notify();  // 기다리고 있는 CUST를 깨우기 위함.
		System.out.println("Dishes:" + dishes.toString());
	}

	public void remove(String dishName) {
		synchronized(this) {	
			String name = Thread.currentThread().getName();

			while(dishes.size()==0) {
					System.out.println(name+" is waiting.");
					try {
						wait(); // CUST쓰레드를 기다리게 한다.
						Thread.sleep(500);
					} catch(InterruptedException e) {}	
			}

			while(true) {
				for(int i=0; i<dishes.size();i++) {
					if(dishName.equals(dishes.get(i))) {
						dishes.remove(i);
						notify(); // 잠자고 있는 COOK을 깨우기 위함 
						return;
					}
				} // for문의 끝

				try {
					System.out.println(name+" is waiting.");
					wait(); // 원하는 음식이 없는 CUST쓰레드를 기다리게 한다.
					Thread.sleep(500);
				} catch(InterruptedException e) {}	
			} // while(true)
		} // synchronized
	}
	public int dishNum() { return dishNames.length; }
}
▷ 실행
class Ex13_15 {
	public static void main(String[] args) throws Exception {
		Table2 table = new Table2();

		new Thread(new Cook2(table), "COOK").start();
		new Thread(new Customer2(table, "donut"),  "CUST1").start();
		new Thread(new Customer2(table, "burger"), "CUST2").start();
		Thread.sleep(2000);
		System.exit(0);
	}
}
▷ 에러 없이 잘 돌아감
// console

Dishes:[donut]
Dishes:[donut, burger]
Dishes:[donut, burger, donut]
Dishes:[donut, burger, donut, donut]
Dishes:[donut, burger, donut, donut, donut]
Dishes:[donut, burger, donut, donut, donut, burger]
COOK is waiting.
CUST2 ate a burger
CUST1 ate a donut
Dishes:[donut, donut, donut, burger, donut]
CUST1 ate a donut
CUST2 ate a burger
Dishes:[donut, donut, donut, donut]
Dishes:[donut, donut, donut, donut, burger]
Dishes:[donut, donut, donut, donut, burger, burger]
COOK is waiting.
CUST2 ate a burger
CUST1 ate a donut
Dishes:[donut, donut, donut, burger, donut]
CUST1 ate a donut
CUST2 ate a burger
Dishes:[donut, donut, donut, donut]
Dishes:[donut, donut, donut, donut, donut]
Dishes:[donut, donut, donut, donut, donut, donut]
COOK is waiting.
CUST2 is waiting.
CUST1 ate a donut
Dishes:[donut, donut, donut, donut, donut, burger]