Java에서 Thread만들기

Jerry Kim·2021년 8월 13일
0

CS_STUDY

목록 보기
4/5

Thread란?

  • 하나의 프로세스가 갖게 되는 실제 작업 수행 단위
    1. 프로그램이 실행되면 OS로부터 메모리를 할당받아 Process상태가 된다
    2. 하나의 프로세스를 CPU가 점유하면서 실질적으로 우리가 컴퓨터내 여러 프로그램을 사용할 수 있는 것이다
    3. CPU가 하나의 프로세스를 점유할 때, 1개 이상의 Thread라고 하는 작업 단위에 의해서 프로세스가 구성되고 각 스레드로 하여금 하나의 작업을 처리하게 된다

                        ∴ 여러 작업이 동시에 실행할 수 있는 효과!



멀티스레딩(multi-threading)

  • thread는 각각 자신만의 작업 공간을 가짐 (context를 가진다고 표현)
  • 각 스레드끼리 공유하는 자원(Shared Resource)이 있을 수 있음 ( -> Java에서는 보통 Static Instance를 공유)
  • 여러 Thread가 자원을 공유할 때, 서로 자원을 차지하려는 Race condition이 발생할 수 있는데, 이렇게 여러 thread가 공유하는 자원중 경쟁이 발생하는 부분을 임계영역(critical section)이라고 함
  • 임계영역에 대한 동기화(Synchronization, 일종의 순차적 수행)를 구현하지 않으면 오류가 발생할 수 있음

∴ 임계영역에 대한 동기화 방법 : 세마포어(Semaphore), 모니터(Monitor) 등등


Thread Status

  • Start가 되면, 쓰레드가 Runnable 상태에 돌입
    *Runnable 상태 : 언제든지 Run될 수 있는, CPU에 의해 실행 될 수 있는 상태

  • JAVA에서는 Sleep(지정된 시간), Wait(), Join() 메서드가 수행되면, 해당 쓰레드가 Not Runnable상태에 돌입(즉, CPU가 점유할 수 없는 쓰레드가 됨)

    • Sleep(지정된 시간) : 지정된 시간까지 Not Runnable상태(시간이 지나면 다시 Runnable로 복귀

    • Wait() : 유효한 자원이 생길 때까지 기다림 -> 유효한 자원이 생기면 프로그램에서 notify(), notifyAll()메서드가 호출되어 Wait에 의해서 Not Runnable상태에 있는 쓰레드를 Runnable상태로 복귀

    • Join() : 두개의 쓰레드 A와 B가 존재하는데 이때, A가 수행되기 위해서는 B의 결과리소스가 필요한 상황일 경우, A쓰레드가 Join()에 의해서 Not Runnable상태에 돌입함. 이후, B쓰레드가 종료되어 결과리소스가 생성되면, A가 Runnable상태로 복귀
      -> 동시에 두 개 이상의 Thread가 실행 될 때 다른 Thread의 결과를 참조 하여 실행해야 하는 경우 join() 함수를 사용

Basic Code :

class MyThread extends Thread{
	//Thread를 상속한 클래스를 start하면 자동으로 run()메서드가 실행됨.
  		public void run(){
        
        				for(int i=0;i<=200;i++){
                        			System.out.println(i+"\t");
                                }
 		}
  }
  
public class ThreadTest{
	public static void main(String[] args) {
		System.out.println(Thread.currentThread()+"start");  //  [Thread를 부른 메서드이름, Priority, Thread가 속한 그룹]
			MyThread t1 = new MyThread();
 			MyThread t2 = new MyThread();  // main에 속한 쓰레드, 직접 만든 t1, t2 => 3가지 쓰레드
            
            		t1.start();
                   t2.start();   
                   System.out.println(Thread.currentThread()+"end"); // main에 속한 쓰레드가 먼저 시작되고 끝나는 것을 확인할 수 있다. 
              
    	}	
}
   	



Thread 우선순위

  • Thread.MIN_PRIORITY(=1) ~ Thread.MAX_PRIORITY(=10)
  • 디폴트 우선순위 : Thread.NORMAL_PRIORITY(=5)
  • 우선순위가 높은 Thread가 CPU의 배분을 받을 확률이 높음

Basic Code :

class PriorityThread extends Thread{
	
	public void run() {
		int sum = 0;
		Thread t = Thread.currentThread();
		System.out.println(t+"start");
		
		for(int i=0;i<=1000000;i++) {
			sum+=i;
		}
		System.out.println(t.getPriority()+"END");
	}
}

public class PriorityTest {

	public static void main(String[] args) {
		for(int i = Thread.MIN_PRIORITY;i<=Thread.MAX_PRIORITY;i++) {
			PriorityThread pt = new PriorityThread();
			pt.setPriority(i);
			pt.start();
		}
	}

}

결과 :

Join()

  • 동시에 두 개 이상의 Thread가 실행 될 때 다른 Thread의 결과를 참조 하여 실행해야 하는 경우 join() 함수를 사용
  • join() 함수를 호출한 Thread가 not-runnable 상태가 감
  • 다른 Thread의 수행이 끝나면 runnable 상태로 돌아옴

  • 시나리오 :

    1부터 50, 51부터 100 까지의 합을 구하는 두 개의 Thread를 만들기

  • Code :
public class JoinTest extends Thread{
	
	int start;
	int end;
	int total;  //멤버변수이므로 default = 0 setting
	
	public JoinTest(int start, int end) {
		this.start = start;
		this.end = end;
	}
	
	public void run() {
		int i;
		for(i = start;i<=end;i++) {
			total += i;
		}
		
	}

	public static void main(String[] args) {
		
		JoinTest jt1 = new JoinTest(1,50);
		JoinTest jt2 = new JoinTest(51,100);
		
		jt1.start();
		jt2.start();
		
		
		try {
			jt1.join();
			jt2.join();
		} catch (InterruptedException e) {  // jt1과 jt2가 Runnable상태로 돌아오지 못했을 경우에도, main 쓰레드가 수행될 수 있도록 
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		int total_sum = jt1.total + jt2.total;
		
		System.out.println("jt1.total : "+jt1.total);
		System.out.println("jt2.total : "+jt2.total);
		System.out.println("total_sum : "+total_sum); // join()추가전 = 0 (jt1.start(), jt2.start()가 아직 실행중인 상태이므로, total_sum에 아무것도 더해지지 않아 0)
	
	
	} 

}



Interrupt()

  • Thread가 join(), sleep(), wait() 함수에의해 not-runnable 상태일 때 interrupt() 메서드를 호출하면 다시 runnable 상태가 될 수 있음

  • 다른 Thread에 예외를 발생시키는 interrupt를 보냄


Thread 종료(Terminate)

시나리오 :

세 개의 thread를 만든다.
각각 무한 루프를 수행하게 한다.
작업 내용 this.sleep(100);
‘A’ 를 입력 받으면 첫 번째 thread를
‘B’ 를 입력 받으면 두 번째 thread를
‘C’ 를 입력 받으면 세 번째 thread를
‘M’을 입력 받으면 모든 thread와 main() 함수를 종료

Code :

import java.io.IOException;

public class TerminateThread extends Thread{

	private boolean flag = false;
	int i;
	
	public TerminateThread(String name){
		super(name);
	}
	
	public void run(){
		
		while(!flag){
			try {
				sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		System.out.println( getName() + " end" );
		
	}
	
	public void setFlag(boolean flag){
		this.flag = flag;
	}
	
	
	public static void main(String[] args) throws IOException {

		TerminateThread threadA = new TerminateThread("A");
		TerminateThread threadB = new TerminateThread("B");
		TerminateThread threadC = new TerminateThread("C");
		
		threadA.start();
		threadB.start();
		threadC.start();
		
		int in;
		while(true){
			in = System.in.read();
			if ( in == 'A'){
				threadA.setFlag(true);
			}else if(in == 'B'){
				threadB.setFlag(true);
			}else if( in == 'C'){
				threadC.setFlag(true);
			}else if( in == 'M'){
				threadA.setFlag(true);
				threadB.setFlag(true);
				threadC.setFlag(true);
				break;
			}else{
				System.out.println("type again");
			}
		}
		
		System.out.println("main end");
		
	}
}


 



    

profile
Welcome to Jerry's World

0개의 댓글