본문 바로가기
Kosta DevOps 과정 280기/Java

쓰레드 통신

by 롯슈83 2024. 5. 30.
  • 두개의 쓰레드가 반드시 1:1로 동작하도록 하려면 쓰레드 상의 통신이 필요합니다. 내가 작업을 하고 있는동안에는 '너는 기다려. ', '내가 작업이 끝났으니 너는 일을 해라.'와 같이 쓰레드 사이의 통신을 이용하면 1:1로 동작하도록 만들 수 있다. 예를 들어 "생산자"와 "소비자"가 있다고 할 때 새로운 제춤이 생산되어야지만 소비가 일어나고 소비가 일어나야지만 새로운 제품을 생산하는 경우에는 둘 사이에 생산이 되었는지 소비가 있었는지 서로 통신이 필요하다. 생산자는 소비가 일어날 때까지 기다렸다가 소비가 되면 새로운 제품을 생산하고 소비자는 생산이 일어날 때까지 기다렸다가 새로운 제품이 생산되면 소비가 일어나도록 반드시 1:1로 동작하도록 할 수 있다. 
  • 자바에서는 이러한 쓰레드 사이의 통신을 위하여 자바의 제일 조상클래스인 Object의 wait과 notify 메소드를 이용한다. 내가 상대방이 일이 완료될 때까지 기다리게 하기 위해서는 wait 메소드를 이용하고 내가 일이 끝나서 상대방을 깨울 때는 notify 메소드를 이용한다.

 

쓰레드 관련메소드

  • Object의 메소드
    • wait은 자기 자신이 기다리는 것
    • notify 는 wait 하는 모두를 깨우는 것
  • Thread 의 메소드
    • join은 내가 할때까지 기다리라고 하는것

 

생산자와 소비자 문제

  • 생산자 -> makeNumber()
  • 소비자 -> useNumber()
  • 제품(공유자원) -> int number,  boolean isNew
  • 소비자는 제품이 만들때까지 소비를 하지 못한다.
  • 생산자는 소비를 해야 새 제품이 만든다
package com.kosta.exam08;

import java.util.Random;

//생산자와 소비자가 공유할 자원인 "제품"클래스를 만든다.
//새로운 정수를 제품이라고 본다.
public class Product {
	//제품을 위한 정수형 변수를 선언한다.
	//생산자는 이 정수를 계속하여 새롭게 만들어주고
	//소비자는 이 정수를 계속하여 가져다 쓰도록 한다.
	int number;
	
	//새 제품이 생산되었는지 판별하기 위한 변수
	//생산자는 새 제품을 생산한 다음 isNew 에 true를 저장하고 소비자는 제품을 소비한 후에isNew 에 false를 저장한다.
	
	boolean isNew;
	
	//생산자가 새 제품을 생산하기 위한 메소드
	//생산자는 새 제품을 생산한 다음 isNew 에 true를 저장
	//생산자가 새 제품을 만들고 있는 동안, 소비자는 접근을 못해야한다. 따라서 임계영역 설정을 위하여 synchronized 키워드를 붙인다.
	public synchronized void makeNumber() {
		try {
			//소비가 일어날 때까지 기다림(wait());
			//즉, isNew가 true가 될 때까지 기다림
			while(isNew == true) {
				wait();
			}
			
			//새 제품을 만든다.
			Random r = new Random();
			number = r.nextInt(100) + 1;
			
			//생산된 제품을 출력
			System.out.println("생산자가 생산함==>"+ number);
			isNew = true;
			
			//대기중인 소비자를 깨워주는 메소드
			notify();
			
		}catch(InterruptedException e) {
			System.out.println("인터럽트 예외");
		}
	}
	
	//소비자가 사용하는 메소드
	public synchronized int useNumber() {
		int n = 0;
		try {
			//생산자가 새로운 제품을 생산할 때까지 기다린다.
			while(isNew == false) {
				wait();
			}
			
			//소비 표시
			n = number;
			System.out.println("소비자가 소비함==>"+ n);
			
			isNew = false;
			
			//다른 스레드 즉, 생산자 깨우기
			notify();
			
		}catch(InterruptedException e) {
			System.out.println("인터럽트 예외");
		}	
		return n;
	}
}
package com.kosta.exam08;

//생산자 클래스 만들기
//소비자와 상관없이 계속하여 새로운 제품을 생산하게 하기 위하여 Thread 클래스를 상속받아 멀티 쓰레드가 가능하도록 한다.
public class Producer extends Thread {
	//제품을 멤버변수로 선언한다.
	private Product product;
	
	//생성시에 제품을 매개변수로 전달받아 초기화한다.
	//이 제품이 소비자와 공유하는 자원이다.
	public Producer(Product product) {
		this.product = product;
	}
	
	public Product getProduct() {
		return product;
	}

	//생산자 쓰레드가 해야 할 일을 run을 오버라이딩 하여 써준다.
	@Override
	public void run() {
		//10개의 새로운 제품을 생산하도록 한다.
		for(int i=1; i<= 10; i++) {
			try {
				
				product.makeNumber();
				Thread.sleep(10);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}	
}
package com.kosta.exam08;

//생산자와 관계없이 계속하여 제품을 소비하도록 하기 위하여 멀티 쓰레드가 되게 한다.
public class Consumer extends Thread{
	private Product product;

	public Consumer(Product product) {
		this.product = product;
	}
	
	//run을 오버라이딩 하여 소비자가 해야할 일을 써준다.
	@Override
	public void run() {
		for(int i = 1; i <= 10; i++) {
			product.useNumber();
			try {
				Thread.sleep(100);
			}catch(InterruptedException e) {
				e.printStackTrace();
			}
		}
	}	
}
package com.kosta.exam08;

public class MainTest {
	public static void main(String[] args) {
		Product p = new Product();
		Consumer c = new Consumer(p);
		Producer p1 = new Producer(p);
		c.start();
		p1.start();
	}
}

'Kosta DevOps 과정 280기 > Java' 카테고리의 다른 글

File메소드  (0) 2024.06.04
GUI와 CUI  (0) 2024.05.30
임계영역 (Critical Section)  (0) 2024.05.30
멀티스레드-2  (0) 2024.05.30
예외 처리  (0) 2024.05.28