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 |