본문 바로가기
츄Log/끄적끄적

멀티스레드 wait(), notify() 실습

by 츄츄🦭 2024. 7. 2.
728x90

 

멀티스레드 프로그래밍에서는 공유자원에 접근하는 스레드 두 개를 동기화처리를 해야합니다.

이 때 여러가지 방법이 있는데요,

busy waiting을 할 수도 있고 특정 시간동안 sleep을 해줄 수 있습니다.

다만 이렇게 하면, 최적의 성능을 얻을 수가 없습니다. 

busy waiting은 CPU를 계속 사용하게 되고,

특정 시간동안의 sleep은 특정 시간을 적절히 설정할 수 없어서 너무 짧으면 busy wait과 비슷하고, 너무 길면 자원을 낭비할 수 있습니다. 

그래서 스레드가 실행을 재개하는 시점을 코드에서 결정할 수 없다면 wait() & notify()를 사용합니다.

 

wait() & notify()를 사용하는 매우 구린 실습코드를 만들어봤습니다.

private static class Adder implements Runnable {

// 글로벌하게 아무 인스턴스 하나 만들고 Main함수에서 adder, remover 스레드를 만들어서 start시켜줬습니다.
// 모니터 객체가 되는 m 인스턴스 또한 글로벌해야겠지요?
		@Override
		public void run() {
			while (true) {
				synchronized (m) {
					list.add(1);
					System.out.println("adder called!" + Thread.currentThread().getName() +" list size : " + list.size());
					m.notifyAll();
                    // 이 안에서 sleep을 하면 안됩니다. 
                    // notify는 단순히 스레드를 재개하는 것이므로 
                    // 이 안에서 잠들면 m을 해제하지 않은 채로 잠들게 됩니다.
				}
                
                // list에 천천히 넣어줍니다. 
				try {
					Thread.sleep(3000);
				} catch (InterruptedException e) {
					throw new RuntimeException(e);
				}
			}
		}
	}

	private static class Remover implements Runnable {
		@Override
		public void run() {
			while(true) {
				synchronized (m) {
					if (list.isEmpty()) {
						try {
							m.wait();
						} catch (InterruptedException e) {
							throw new RuntimeException(e);
						}
					}
					list.remove(0);
					System.out.println("remover called!"+ Thread.currentThread().getName());
				}
			}
		}
	}

 

wait() : 주어진 조건을 만족하면, wait으로 스레드에게 대기하라고 지시합니다.

이 스레드는 자신이 대기하는 동안 다른 스레드가 동기화 블록에 들어올 수 있도록 모니터의 락을 해제합니다.

notify() : 대기중인 스레드가 실행을 재개하도록 지시합니다. 

 

 

초록색 : running - 실행중으로 CPU가 커맨들을 실행중인 상태입니다.

하늘색 : monitor - 스레드가 동기화블록의 모니터에 의해 중단되고 해당블록을 실행하기 위해 해제를 기다리는 상태입니다.

노란색 : wait - 실행 도중 모니터의 wait()메서드가 호출되어 현재 스레드가 중단된 상태입니다. notify(), notifyAll()메서드가 호출될 때까지 스레드는 차단된 상태를 유지합니다. 

728x90