Java

[Java] Multithread Programming

안도일 2022. 12. 18. 16:36

Multithread

 

thread가 둘 이상인 프로그램을 Multithread라고 한다.

main 메소드의 첫 번째 명령문부터 실행 (main thread) 이 시작된다.

main thread 는 program 이 시작되면 자동으로 시작되지만, 다른 thread 는 main thread 에서 만들어 시작해야 함.

이 thread 들은 시작되고 나면 main thread 와 동등한 레벨이 됨.

main thread 가 끝나더라도 다른 thread 는 실행을 계속할 수 있음.

main thread 가 끝났다고 해서 program 이 끝나는 것이 아니라, 모든 thread 가 끝나야만 완료되는 것임.

 

자바책 18-1 multithread programming

 

Multithread programming은 아래 두 가지 방법으로 작성할 수 있다.

 

java.lang.Thread 클래스를 이용

java.lang.Runnable 인터페이스를 이용

 

 

Multithread program - java.lang.Thread

 

A~Z까지 출력하는 thread와 0~9까지 출력하는 thread를 만들어 실행시켜보자

Thread 클래스를 상속받아 0~9를 차례로 출력하는 DigitThread를 생성하고 main에서 DigitThread를 start

 

public class DigitThread extends Thread { 

	public void run(){ //Thread의 run 메소드 오버라이딩
		for (int cnt =0; cnt<10; cnt++) {
			
			System.out.print(cnt);
		
			try {
				Thread.sleep(100);
			}
			catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

 

public class MultiThreadExam01 {

	public static void main(String[] args) {
		
		Thread th = new DigitThread(); //다형성

		th.start();
		
		for(char ch = 'A'; ch <= 'Z'; ch++) { //main Thread
			System.out.print(ch);
		
			try {
				Thread.sleep(100);
			}
			catch (InterruptedException e) {
				e.printStackTrace();
			}
		
		}
	}
}

 

숫자와 알파벳이 패턴없이 섞여서 출력된다. -> 동시에 실행 중이라는 뜻

실제로 thread 가 동시에 실행되는 것은 아니다.  실행 시간을 아주 작은 간격으로 나누어 thread 들을 번갈아 실행할 뿐이며  thread에 할당하는 시간과 실행 순서는 하드웨어의 성능과 시스템 환경에 따라 달라질 수 있다.

 

 

Multithread program - java.lang.Runnable

 

ㄱ~ㄴ 까지 출력하는 thread와 a~z 까지 출력하는 thread를 만들어 실행시켜보자

Runnable 클래스를 구현해 a~z를 차례로 출력하는 SmallLetters를 생성하고 main에서 SmallLetters를 start

 

public class SmallLetters implements Runnable{ 
	//Runnable은 인터페이스 이므로 implements , 자바는 다중상속이 안되기 때문에 Runnable을 사용해야만 하는 경우가 있음

	public void run() {
		
		for(char ch='a'; ch<'z'; ch++) {
			System.out.print(ch);
		}
	}
}

 

public class MultiThreadExam03 {

	public static void main(String[] args) {
		
		Thread th = new Thread( new SmallLetters() );
		
		th.start();
		
		char arr[] = {'ㄱ','ㄴ','ㄷ','ㄹ','ㅁ','ㅂ','ㅅ','ㅇ','ㅈ','ㅊ','ㅋ','ㅌ','ㅍ','ㅎ'};
		
		for(char ch : arr) {
			System.out.print(ch);
		}
	}
}

 

자바는 다중상속을 허용하고 있지 않기 때문에 다중 상속을 피해야 할 경우 Runnable을 구현하는 방식으로 사용해야 한다. 

 


공유 영역

 

thread들이 서로 무관하게 실행되기도 하지만 경우에 따라 서로 데이터를 교환해야 할 경우도 있다. 즉 두 thread 간의 communication이 필요할 때가 있다.

두 thread가 데이터를 교환하는 기본적인 방법은 두 thread 모두 접근 가능한 메모리 영역을 만들어 둔 후, 한 쪽 thread는 그 영역에 데이터를 쓰고, 다른 thread는 데이터를 읽는 방식이다.

 

 

원주율 계산 Multithread program

 

원주율을 계산하는 thread와 그 결과값을 출력하는 thread를 만들어 보자

 

public class SharedArea {
	
	double result;
	boolean isReady;
}

 

아래에서 작성할 CalcThread와 PtrThread가 공유하는 영역 SharedArea를 생성

공유 영역은 레퍼런스 타입으로 선언해야 여러 thread  참조값을 가지고 접근할 수 있다.

result에는 CalcThread가 생성한 결과값을 저장

isReady에는 CalcThread가 공유 데이터 result를 작성 후 isReady 값을 True로 바꿔 PtrThread에게 알려준다.

 

 

 

public class CalcThread extends Thread{

	SharedArea sA;
	
	public void run(){
		
		double total = 0.0;

        for (int cnt=1; cnt<10000; cnt+= 2) {

            if (cnt/2%2 == 0)
                total += 1.0/cnt;
            else
                total -= 1.0/cnt;
        }
        
        sA.isReady = true;
        sA.result = total * 4;
        
        synchronized (sA) {
            sA.notify();
		}
	}
}

 

CalcThread 가 공유 영역에 데이터를 쓰고 난 다음에,  isReady의 필드 값을 true 로 설정하면,

PrtThread 는 그 값을 가지고 공유 데이터의 유무를 체크할 수 있다.

 

 

public class PrtThread extends Thread{
	
	SharedArea sA;
	
	public void run() {
	//	while (sA.isReady != true)
	//		continue;
		
		if(sA.isReady != true) {
			try {
				synchronized (sA) {
					sA.wait();
				}
				
			}catch(InterruptedException e) {
				e.printStackTrace();
			}
		}
	
		System.out.println(sA.result);
	}

}

PtrThread는 공유 영역의 isReady 값이 true가 될 때까지 무한히 루프를 돌아야 한다 -> 매우 비효율적임

 

따라서 CalcThread가 값을 입력하고 PtrThread에게 직접 신호를 보내자 (synchronization)

 

critical section

-  thread 실행 중에 다른 thread 로 제어가 넘어가면 문제를 일으킬 수 있는 부분

-  주로 공유 데이터를 사용하는 부분

 

critical section의 synchronization

-  critical section 이 실행되는 동안 다른 thread 가 공유 데이터를 사용할 수 없도록 만드는 것

 

 

 

public class MultiThreadExam04 {

	public static void main(String[] args) {
		
		CalcThread th1 = new CalcThread();
		PrtThread th2 = new PrtThread();
		SharedArea obj = new SharedArea();
		
		th1.sA = obj;
		th2.sA = obj;
		
		th1.start();
		th2.start();

	}

}