[JAVA] THREAD(쓰레드)

Thread, Thread 생성주기, Runnable

Posted by iheese on April 29, 2022 · 7 mins read

Thread

  • 하나의 프로세스(동작하고 있는 프로그램) 내부에서 독립적으로 실행되는 하나의 작업 단위
  • 보통 한 개의 프로세스는 한 개의 작업을 하지만 쓰레드를 이용해 여러가지 일을 동시에 할 수 있다.(멀티쓰레딩)
  • JVM에 의해 하나의 프로세스가 발생하고 main() 안의 실행문이 하나의 쓰레드이다.
  • 이외의 쓰레드를 만드려면 Thread 클래스 상속, Runnable 인터페이스를 구현하면 된다. (Runnable은 자바가 다중 상속을 허용치 않기 때문에 존재함)


Thread 생성주기

thread

  • Runnable : 쓰레드 실행 준비
    • CPU를 점유하고 있지 않은 상태
    • start() 메소드 호출하면 run() 메소드가 수행되도록 내부적으로 동작하고 해당 쓰레드가 Runnable 상태로 진입한다.
  • Running : 스케줄러에 의해 선택된 쓰레드 실행
    • CPU를 점유하고 실행하는 상태
    • run()은 JVM 만 호출 가능하며 스케줄러에 따라 Runnable의 쓰레드를 Running 상태로 진입한다.
  • Blocked : 쓰레드 작업 중 멈추는 상태
    • CPU 점유권 상실한 상태
    • sleep(시간) 메소드는 시간이 지난 후 Runnable 상태로 바뀐다.
    • wait() 메소드는 notify() 메소드가 호출되면 Runnable 상태로 바뀐다.
  • Dead : Running 상태 이후의 완료 상태


Thread 실습

class ThreadEx extends Thread{
		public void  run() {  //run() 메소드를 재정의 해야한다.
			System.out.println("Thread Run");
		}
}

public class ThreadTest {
	public static void main(String[] args) {
		ThreadEx threadEx = new ThreadEx();
		threadEx.start(); //Thread Run
	}
}
  • 한 개의 쓰레드를 만들어서 실행해보았다.
  • 여러 개의 쓰레드는 어떻게 움직이는지 실행해보면 좋을 것 같다.


class ThreadEx extends Thread{
		int num;
		public ThreadEx(int num) {
			this.num=num;
		}
		
		public void  run() {  //run() 메소드를 재정의 해야한다.
			System.out.println(this.num+" Thread Run");
			try {
				Thread.sleep(2000); //2초 뒤 재실행
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(this.num+" Thread end");
		}
}

public class ThreadTest {
	public static void main(String[] args) {
		for(int i = 0; i<10; i++) {
			ThreadEx threadEx = new ThreadEx(i);
			threadEx.start();
		}
		System.out.println("main end");
	}
}
  • 10개의 쓰레드를 만들어 실행했고 종료했다. 중간에 main 메소드가 종료되었다.
  • 쓰레드 실행과 종료가 무작위로 이루어졌다. 실행과 종료에는 순서가 정해져 있지 않다. 종료시 main도 해당되는 이야기이다.


  • 모든 쓰레드가 실행되고 종료된 뒤 main 메서드를 종료하게 하려면 join 매소드를 이용하면 된다.
import java.util.ArrayList;

class ThreadEx extends Thread{
		
		int num;
		public ThreadEx(int num) {
			this.num=num;
		}
		
		 
		public void  run() {  //run() 메소드를 재정의 해야한다.
			System.out.println(this.num+" Thread Run");
			try {
				Thread.sleep(2000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(this.num+" Thread end");
		}
}

public class ThreadTest {
	public static void main(String[] args) {
		ArrayList<ThreadEx> threads= new ArrayList<>();
		for(int i=0; i<10; i++) {
			ThreadEx threadEx = new ThreadEx(i);
			threadEx.start();
			threads.add(threadEx);
		}
		
		
		for(int j = 0; j<threads.size(); j++) {
			ThreadEx thread= threads.get(j);
			try {
				thread.join();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println("main end");
	}
}


Runnable 인터페이스

  • 클래스가 다른 클래스를 이미 상속한 경우 Runnable 인터페이스를 이용하자
class ThreadImple implements Runnable{
	public void  run() {  //run() 메소드를 재정의 해야한다.
		System.out.println("Thread Run");
	}
} 	//Runnable 인터페이스 구현
	//Runnable을 구현한 객체는 run() 메소드에만 접근할 수 있다. 

public class ThreadTest2 {

public static void main(String[] args) {
		ThreadImple threadEx = new ThreadImple();
		Thread threadImple= new Thread(threadEx); 
        //Thread 생성자에 넣어 사용
		threadImple.start();
		
	}
}
  • Runnable을 구현한 객체를 Thread 생성자로 넘겨 사용한다.
    • 물론 Thread를 상속받는 방법이 조금 더 간단하지만 다중상속이 불가한 자바에서 Runnable 인터페이스을 구현한 객체를 이용하는 방법이 더 선호된다.


Reference: