wait(), notify()
- wait()
- 동기화 영역에서 락을 풀고 Wait-Set영역 (공유객체별 존재)으로 이동시킨다.
- notify() 또는 notifyAll()
- Wait-Set 영역에 있는 쓰레드를 깨워서 실행할 수 있도록 한다.
- nofity()는 하나, notifyAll()은 Wait-Set에 있는 전부를 깨운다
- notify(): 랜덤이라 내가 원하는 애 말고 다른 애들을 깨울 수도 있음, 그럴바엔 그냥 notifyAll로 한번에 다 깨우는게 나음
- wait, notify, notifyAll 모두 동기화 영역에서만 실행 가능
- Object 클래스에서 제공하는 메서드이다
예시
쌤
- 내가 스레드 1번, 공유객체 문열고 들어가, 작업다끝나고나면 락 풀어놔 ,사람들 들어올수있게
- 2번이 거기 들어갔어, 잠궈놓고 일보고 다시 나와서 다시 풀어놓고 나가고
- wait-set 영역
- 대기실 같은 곳, 내가 지금 동기화영역에서 할 일이없어가지고 일시정지할라고 대기실 ㄱㄱ
- 대기실은 공유객체에 대한 대기실, 각 공유객체마다 대기실이 따로따로 있음
- 대기실에서 기다리는동안은 (=공유객체에서 나올때) 락풀고나와야함 다른사람들 들어갈수있게
- notify안받으면 영원히 대기실에......
- 딴사람이 작업하다가 할일 다하면 나 notify로 꺠우고 나도 일어나서 일하다가 다시 wait하면서 wait-set에서 기다리고 또 notify 하고 일하고
T19
1단계) 공유객체 클래스
class WorkObject {
public synchronized void MethodA() {
System.out.println("methodA에서 작업 중...");
notify();
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void methodB() {
System.out.println("methodB에서 작업 중...");
notify();
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
2단계) WorkObject의 methodA()메서드만 호출하는 쓰레드 클래스
class ThreadA extends Thread {
private WorkObject workObj;
public ThreadA(WorkObject workObj) {
this.workObj = workObj;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
workObj.methodA();
}
System.out.println("ThreadA 종료");
}
}
3단계) WorkObject의 methodB()메서드만 호출하는 쓰레드 클래스
class ThreadB extends Thread {
private WorkObject workObj;
public ThreadB(WorkObject workObj) {
this.workObj = workObj;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
workObj.methodB();
}
System.out.println("ThreadB 종료");
}
}
4단계) 메인에서 실행
public static void main(String[] args) {
WorkObject workObj = new WorkObject();
ThreadA tha = new ThreadA(workObj);
ThreadB thb = new ThreadB(workObj);
tha.start();
thb.start();
}
결과
- B를 깨워줄 A가 종료되어서 B는 영원히 잠들게되었따.......
- 프로그램을 종료할 방법이 없음
T20
1단계) 공유 객체 클래스
class DataBox {
private String data;
public synchronized String getData() {
if(data == null) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
String returnData = data;
System.out.println("읽어온 데이터 : " + returnData);
data = null;
System.out.println(Thread.currentThread().getName() + "notify()호출");
notify();
return returnData;
}
public synchronized void setData(String data) {
if(this.data != null) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.data = data;
System.out.println("셋팅한 데이터 : " + this.data);
System.out.println(Thread.currentThread().getName() + "notify()호출");
notify();
}
}
2단계) 데이터를 셋팅만 하는 쓰레드
class ProducerThread extends Thread {
private DataBox dataBox;
public ProducerThread(DataBox dataBox) {
super("ProducerThread");
this.dataBox = dataBox;
}
@Override
public void run() {
for(int i=1; i <= 10; i++) {
String data = "Data-" + i;
System.out.println("dataBox.setData("+data+")호출");
dataBox.setData(data);
}
}
}
3단계) 데이터를 읽어만 오는 쓰레드
class ConsumerThread extends Thread {
private DataBox dataBox;
public ConsumerThread(DataBox dataBox) {
super("ConsumerThread");
this.dataBox = dataBox;
}
@Override
public void run() {
for (int i = 1; i <= 10; i++) {
String data = dataBox.getData();
System.out.println("dataBox.getData() : " + data);
}
}
}
4단계) main에서 실행
public static void main(String[] args) {
DataBox dataBox = new DataBox();
ProducerThread pth = new ProducerThread(dataBox);
ConsumerThread cth = new ConsumerThread(dataBox);
pth.start();
cth.start();
}