qordpsem 2024. 5. 30. 09:31

#프로세서

실행 중인 프로그램

 

#멀티프로세서

동시에 여러 프로그램이 실행되는 것

 

#쓰레드

프로그램 안에서 실행 중인 메소드

 

#멀티 쓰레드

프로그램 안에서 여러개의 메소드가 동시다발로 동작하는 것

 

#자바에서는 멀티 쓰레드 프로그래밍을 위하여

Thread 클래스Runnable 인터페이스를 이용 할 수 있다!

 

쓰레드가 해야하는 일은 run()메소드를 오버라이딩해서 그 안에 쓰고,

쓰레드를 동작시키기 위해서는 start()메소드를 호출한다

 

쓰레드를 가동시키기 위해서 start()를 호출해야하는데 run()을 호출하면 ?

=> 오류가 난다? X

=> 쓰레드가 가동되지 않고, 일반 메소드처럼 동작함

 

 


 

 

class Hello implements Runnable{
	public void run() {
		 .............
  	}
}


Hello h = new Hello();
(new Thread(h)).start();

 

=> 직접 start 호출 불가. Thread 통해서 start 호출해야함

 

 

 

#Thread 우선순위 설정

필요하다면 우선순위 설정 가능

가급적 다른것 보다 먼저 해줘~ 라는거지 항상 더 빨리되는거 아님

ex ) a.setPriority(Thread.MAX_PRIORITY)

 

 

#임계영역

두 개 이상의 쓰레드가 자원을 공유할때 한번에 하나의 쓰레드에게만 접근 허용하는 영역

자바에서는 그러한 동작을 하는 메소드 이름 / 그런 기능을 하는 블럭{} 앞에 synchronized 키워드 붙이면

자동으로 임계영역이 돼서 한번에 하나의 쓰레드에게만 접근 허용

 

 

5명이 1000원씩 10번 입금하면

50000원이 되어야 하는데 이상함

 

공유자원에 두 개 이상의 쓰레드가 한번에 접근해서 이런현상이 있을 수 있음

한번에 하나의 쓰레드에게만 접근을 허용하려면 임계영역을 설정해야함

자바에서는 임계영역설정을 위하여 메소드 이름 앞에 synchronized 키워드를 붙여줌

 

 

쓰레드를 가동시키면 가능한 동시다발로 공평하게 실행 되게 스케줄링 해줌

만약 두 개의 객체가 반드시 일대일로 동작하도록 하려면 쓰레드 사이의 통신을 이용할 수 있음

 

#쓰레드 사이의 통신

두 개의 쓰레드가 반드시 1:1로 동작하게 하려면 쓰레드 사이의 통신이 필요함

ex) 생산자, 소비자 -> 생산 되어야 소비 일어나고, 소비 일어나야 생산 -> 둘 사이에 생산, 소비 됐는지 서로 통신 필요

생산자는 소비가 일어날때까지 기다렸다가 소비되면 새로운 제품을 생산하고 소비자는 생산이 일어날때 가지 기다렸다가 새로운게 생산되면 소비가 일어나도록 1:1로 동작할 수 있음

쓰레드 통신 위해  Obejct와 wait, notify 이용

내가 일 완료될때까지 기다리게 위해서 wait 메소드 이용

일 끝나서 상대 깨울땐 notify 를 이용

 

 

import java.util.Random;

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

 

 

// 생산자 클래스를 만들기
// 소비자와 상관없이 계속하여 새로운 제품을 생산케 하기위하여
// Thread클래스를 상속받아 멀티쓰레드가 가능하도록 하기
public class Producer extends Thread {
	//제품을 맴버변수로 선언
	private Product product;
	// 생성시에 제품을 매개변수로 전달받아 초기화
	// 이 제품이 소비자와 공유하는 자원
	public Producer(Product product) {	
		this.product = product;
	}
	//생산자 쓰레드가 해야 할 일을 run을 오버라이딩 하여 써주기
	public void run() {
		// 10개의 새로운 제품을 생산하도록 합니다.
		for(int i=1; i<=10; i++) {
			try {
				product.makeNumber();
				Thread.sleep(100);
			}catch (Exception e) {
			}
		}
	}
}

 

// 소비자 클래스
// 생산자와 상관없이 계속하여 제품을 소비하도록 하기 위해 멀티쓰레드가 되게 하기
public class Consumer extends Thread {
	//생산자와 제품을 공유하기 위하여 맴버변수로 제품을 선언
	private Product product;
	//생성시에 제품을 매개변수로 전달받아 초기화 합니다.
	public Consumer(Product product) {
		this.product = product;
	}
	// run을 오버라이딩 하여 소비자가 해야할 일을 써주기
	public void run() {
		for(int i=1; i<=10; i++) {
			product.useNumber();
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {				
			}
		}
	}
}
public class ManTest {
	public static void main(String[] args) {
		Product product = new Product();
		Producer producer = new Producer(product);
		Consumer consumer = new Consumer(product);
		producer.start();
		consumer.start();
	}
}