위로 아래

스레드 생명 주기

스레드 생명 주기

  1. 생성 -> 준비 -> 실행 -> 보류(입출력 후) 또는 대기 -> 준비 반복
  2. 마지막엔 생성 -> 준비 -> 실행 -> 종료

 

특징

  1. 우선순위 개념이 없다
  2. start() 하면 준비 상태가 된다
  3. run() 하면 실행 상태가 된다

 

스레드의 상태 확인

  1. getState() 메소드 사용.
  2. 스레드 상태에 따라 다음 상수를 반환
상태 상수 설명
객체 생성 NEW 객체를 생성한 후 아직 시작하지 않은 상태
실행 대기 RUNNABLE 실행 준비가 된 상태
중지 BLOCKED 입출력 등 락(Lock)이 풀릴 때까지 기다리는 상태
WAITING 다른 스레드가 통지할 때까지 기다리는 상태
TIME_WAITING 주어진 시간 동안 기다리는 상태
종료 TERMINATED 실행을 마친 상태

 

 

Thread 클래스가 제공하는 상태 제어 메소드

  1. intrerrupt() : 실행 중인 스레드에 인터럽트를 걸어 중지시킨다
  2. join() : 주어진 시간이 지나거나 대응하는 스레드가 종료될 때까지 대기시킨다
  3. resume() : 중지 상태의 스레드를 실행 대기 상태로 전환시킨다
  4. static void sleep() : 주어진 시간 동안 중지한다.
  5. start() : 스레드를 실행 대기시킨다
  6. stop() : 스레드를 종료한다
  7. suspend() : 스레드를 중지한다
  8. yield() : 우선순위가 동일한 스레드에 실행을 양보한다.

 

 


스레드 종료

  1. 스레드는 run() 메소드를 마치면 보류 상태로 넘어간다.
  2. stop() 메소드를 사용하면 스레드를 불완전하게 종료한다.
  3. 스레드를 안전하게 종료하는 방법
    1. 반복문 조건 사용
    2. interrupt() 메소드

 

반복문 조건 사용 예시

더보기
public class StopThread extends Thread {
	public boolean stop;
	
	public void run() {
		while(!stop) {
			System.out.println("실행 중...");
			try {
				Thread.sleep(1);
			} catch (InterruptedException e) {}
		}
		System.out.println("정상 종료");
	}
}
public class StopDemo {
	public static void main(String[] args) {
		StopThread t = new StopThread();
		t.start();
		
		try {
			Thread.sleep(3);
		} catch (InterruptedException e) {}
		t.stop = true;
	}
}

 

interrupt() 메소드 예시

더보기
public class Interrupt1Demo {
	public static void main(String[] args) {
		Runnable task = () -> {
			try {
				while(true) {
					System.out.println("실행 중...");
					Thread.sleep(1);
				}
			} catch (InterruptedException e) {
				System.out.println("인터럽트 : "+e.getMessage());
			}
			System.out.println("정상 종료");
		};
		
		Thread t = new Thread(task);
		t.start();
		
		try {
			Thread.sleep(3);
		} catch(InterruptedException e) {}
		t.interrupt();
	}
}

 

 

 

 


Join() 메소드

  1. 다른 스레드가 종료될 때까지 기다리게 하는 메소드
  2. 다른 스레드가 종료된 후에 스레드가 실행되어야 한다면 사용할 수 있다.

예시

더보기
//JoinThread 클래스 파일
public class JoinThread extends Thread{
	int total;
	
	public void run() {
		for(int i = 1; i <=100 ; i++)
			total += i;
	}
}
public class JoinDemo {
	public static void main(String[] args) {
		JoinThread t = new JoinThread();
		t.start();
		
//		try {
//			t.join();
//			System.out.println("스레드 t가 끝날 때까지 대기...");
//		} catch (InterruptedException e) {}
		System.out.println("총합 : " + t.total);
	}
}
// 숫자 더하는 거 안 기다리고 출력부터 해버린다.
public class JoinDemo {
	public static void main(String[] args) {
		JoinThread t = new JoinThread();
		t.start();
		
		try {
			t.join();
			System.out.println("스레드 t가 끝날 때까지 대기...");
		} catch (InterruptedException e) {}
		System.out.println("총합 : " + t.total);
	}
}
// 숫자 더하는 거 다 기다렸다가 출력 스레드 실행

 

 

 

스레드 스케쥴링

스레드 스케줄링(thread scheduling)

  1. 스레드 개수가 CPU 코어 개수보다 많으면, 스레드에 CPU 타임슬롯을 어떤 방식으로 배정할지 결정해야 한다.
  2. 우선순위 방식 : 우선순위가 높은 스레드가 CPU 자원을 더 자주 사용할 수 있도록 하는 것
  3. 순환할당(round-robin) 방식 : 각 스레드가 차례대로 번갈아가면서 CPU 자원을 사용하는 것

 

우선순위 방식

  1. 낮은 순위부터 1~10이란 정수 부여, 기본 우선순위 값으로 모든 스레드게 5를 부여
  2. Thread 클래스가 제공하는 우선순위 상수
    1. MAX_PRIORITY : 최고 우선순위인 10을 나타내는 상수
    2. NORM_PRIORITY : 중간 우선순위인 5를 나타내는 상수
    3. MIN_PRIORITY : 최저 우선순위인 1을 나타내는 상수

 

예시

더보기
public class Counter extends Thread {
	private int count = 0;
	
	public Counter(String name) {
		setName(name);
	}
	
	public void run() {
		while(count++ < 5) {
			System.out.print(getName() + " -> ");
			try {
				sleep(500);
			} catch (InterruptedException e) {
				
			}
		}
	}
}
public class PriorityDemo {
	public static void main(String[] args) {
		Counter c1 = new Counter("느긋한");
		c1.setPriority(Thread.MIN_PRIORITY);
		Counter c2 = new Counter("급한");
		c2.setPriority(Thread.MAX_PRIORITY);
		c1.start();
		c2.start();
	}
}

급한이 먼저 실행

 

 

 


데몬 스레드

데몬 스레드(daemon thread)

  1. 메인 스레드가 종료되면 함꼐 종료되는 보조 작업 스레드
  2. 우선순위가 가장 낮다

 

제공하는 메소드

  1. setDaemon(boolean status) : 데몬 스레드 여부를 설정한다. start() 메소드 호출 이전에 사용한다.
  2. isDaemon() : 데몬 스레드 여부를 반환 (boolean)

 

예시

더보기
//데몬 스레드가 아닐 시
public class DaemonDemo {
	public static void main(String[] args) {
		Runnable task = () -> {
			for(int i=0 ; i<3 ; i++) {
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {}
				System.out.println(Thread.currentThread().getName());
			}
		};
		
		Thread t1 = new Thread(task, "작업 스레드");
		//t1.setDaemon(true);
		t1.start();
		
		try {
			Thread.sleep(1000);
		} catch(InterruptedException e) {}
		System.out.println("메인 스레드가 끝났습니다.");
	}
}
//데몬 스레드가 있을 시

public class DaemonDemo {
	public static void main(String[] args) {
		Runnable task = () -> {
			for(int i=0 ; i<3 ; i++) {
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {}
				System.out.println(Thread.currentThread().getName());
			}
		};
		
		Thread t1 = new Thread(task, "작업 스레드");
		t1.setDaemon(true);
		t1.start();
		
		try {
			Thread.sleep(1000);
		} catch(InterruptedException e) {}
		System.out.println("메인 스레드가 끝났습니다.");
	}
}