프로그래밍/Java 공부

JAVA - Thread(스레드)

개발계발게발 2021. 6. 30. 17:51
반응형

Thread(스레드)

하나의 프로세스 내부에서 독립적으로 실행되는 하나의 작업 단위

운영체제에 의해 관리되는 하나의 작업 혹은 태스크를 의미

스레드와 태스크(혹은 작업)는 바꾸어 사용해도 무관하다.

 

JVM에 의해 하나의 프로세스가 발생하고 main( ) 안의 실행문들이 하나의 스레드

 

main( ) 이외의 또 다른 스레드를 만들려면 Thread 클래스를 상속하거나 Runnable 인터페이스를 구현 필요

 

스레드 생성 두 가지  방법

  • Thread 클래스를 상속받아 사용
  • Runnable 인터페이스를 사용

실행은 run()을 start()해서 사용

 

어떤 다른 클래스를 extends 해야 하는 상황인데 스레드로도 구현해야 할 때(자바에서 다중 상속은 지원 X)

extends 할 부모 클래스도 스레드를 상속하고 있지 않은 상황이면 Runnable 인터페이스를 구현하여 사용

 

다중 스레드 작업 시에는 각 스레드끼리 정보를 주고받을 수 있어 처리 과정의 오류를 줄일 수 있다.

 

프로세스끼리는 정보를 주고받을 수 없다.

 

자바 스레드를 이용하면 하나의 프로세스에서도 병렬 처리, 여러 개의 처리 루틴을 가질 수 있다.

단순 반복의 코드를 실행할 때도 여러 개의 스레드를 만들어서 분리 시킨 뒤 결과 데이터를 받아 합치면

그만큼 시간을 절약할 수 있다.

 

Thread 라이프 사이클

New 상태 (생성)

  • 스레드 클래스가 키워드 new를 통해서 인스턴스화 된 상태를 말한다.
  • 이 상태는 아직 JVM에 의해서 관리가 되는 스레드의 상태는 아니다. (자바에서는 이 상태부터 스레드라 한다)

 

Runnable 상태 (준비상태)

  • 스레드가 실행되기 위한 준비단계.
  • CPU를 점유하고 있지 않으며 실행(Running 상태)을 하기 위해 대기하고 있는 상태.
  • 코딩 상에서 start( ) 메서드를 호출하면 run( ) 메소드에 설정된 스레드가 Runnable 상태로 진입.
  • 스케줄러에 의해서 선택되어 실행될 수 있기만을 기다리는 상태를 말한다.
  • 스케줄러에 의해 실행의 대상으로 선택이 되어야 비로소 run메소드가 처음 호출이 된다.

 

Blocked 상태 (지연상태)

  • CPU 점유권을 상실한 상태.
  • sleep, join 메소드를 호출하거나 CPU 할당이 필요치 않는 입출력 연산을 하게 되면
  • CPU를 다른 스레드에게 양보하고 자기 자신은 Blocked상태가 된다.
  • 이 상태가 되면 스케줄러의 선택을 받을 수 없다.
  • 입출력 작업이 완료되거나 sleep 메소드가 반환되거나 하는 방식으로 다시 Runnable 상태로 변경된다.
  • wait( ) 메소드에 의해 Blocked 상태가 된 스레드는 notify( ) 메소드가 호출되면 Runnable 상태로 간다.
  • sleep(시간) 메소드에 의해 Blocked 상태가 된 스레드는 지정된 시간이 지나면 Runnable 상태로 간다.

 

 

Running (실행상태)

  • CPU를 점유하여 실행하고 있는 상태이며 run() 메서드는 JVM만이 호출 가능.
  • Runnable(준비상태)에 있는 여러 스레드 중 우선순위를 가진 스레드가 결정되면
  • JVM이 자동으로 run( ) 메소드를 호출하여 스레드가 Running 상태로 진입.

 

Dead 상태 (종료 상태)

  • Running 상태에서 스레드가 모두 실행되고 난 후 완료 상태
  • run메소드의 실행이 완료되어 빠져나오게 되면 Dead상태가 된다.
  • 한 번 Dead상태가 되면 다시 Runnable 상태로 될 수 없다.
  • 스레드 실행을 위해 필요한 모든 것이 소멸되기 때문.

 

예제

Thread01  (Thread상속받아 사용)

public class Thread01 extends Thread {
	public void run() {
		System.out.println("스레드 시작");
	}
	public static void main(String[] args) {
		Thread01 t01 = new Thread01();
		t01.start();
	}
}

실행결과


Thread02  (Thread상속받아 사용)

public class Thread02 extends Thread{
	int seq;
	public Thread02(int seq) {
		this.seq = seq;
	}
	
	@Override
	public void run() {
		System.out.println(this.seq + " 스레드 시작");
		try {
			Thread.sleep(1000);	//1000 
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(this.seq + " 스레드 끝");
	}	
	public static void main(String[] args) {
		System.out.println("메인 시작");
		for (int i = 0; i < 10; i++) {
			Thread02 t02 = new Thread02(i);
			t02.start();
		}		
		System.out.println("메인 끝");
	}
}

실행결과


Thread03  (Thread 상속받아 사용) - join() 사용

import java.util.ArrayList;
//join()
public class Thread03 extends Thread{
	int seq;
	public Thread03(int seq) {
		this.seq = seq;
	}
	@Override
	public void run() {
		System.out.println(this.seq + " 시작");
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(this.seq + " 끝");
	}
	public static void main(String[] args) {
		System.out.println("메인 시작");
		
		ArrayList<Thread> threads = new ArrayList<Thread>();
		
		for (int i = 0; i < 10; i++) {
			Thread03 t03 = new Thread03(i);
			t03.start();
			threads.add(t03);
		}
		
		for (int i = 0; i < threads.size(); i++) {
			Thread t = threads.get(i);
			try {
				t.join();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}		
		System.out.println("메인 끝");
	}
}

실행결과


Thread04 - Runnable 인터페이스로

 

import java.util.ArrayList;
//interface로 Runnable
class AAA{		
}	//자바에서는 다중 상속 허용 X(이럴경우 인터페이스로)
public class Thread04 extends AAA implements Runnable {
	int seq;						
	public Thread04(int seq) {
		this.seq = seq;
	}
	@Override
	public void run() {
		System.out.println(this.seq + " 스레드 시작");
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}		
		System.out.println(this.seq + " 스레드 끝");
	}	
	public static void main(String[] args) {
		System.out.println("메인 시작");
		ArrayList<Thread> threads = new ArrayList<Thread>();
		
		for (int i = 0; i < 10; i++) {
			Thread t = new Thread(new Thread04(i));
			//Thread의 생성자로 Runnable을 구현한 객체를 넘긴다.
			t.start();		
			threads.add(t);
		}
		for (int i = 0; i < threads.size(); i++) {
			Thread t = threads.get(i);			
			try {
				t.join();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}		
		System.out.println("메인 끝");
	}
}

실행결과

반응형