[JAVA] Runnable 인터페이스와 Thread 클래스(sleep, join, interrupt)

Thread 클래스

Thread 클래스는 스레드를 구현하는 데 사용되는 클래스입니다. Thread 클래스를 상속하여 스레드를 구현할 수 있습니다.

 

Thread 클래스의 주요 메서드

  • run() : 스레드가 실행할 코드를 정의하는 메서드입니다. 이 메서드를 오버라이딩하여 스레드가 수행할 작업을 구현합니다.
  • start() : 스레드를 시작하는 메서드입니다. 스레드를 실행 가능한 상태로 전환하고 스케줄러에 의해 선택될 수 있게 합니다. JVM은 이 스레드의 run 메소드를 호출합니다.
  • sleep(long ms) : 일시적으로 스레드를 일시 정지시키는 메서드로, 지정한 시간(ms) 동안 실행을 중지시킵니다.
  • join() : 다른 스레드의 종료를 기다리는 메서드로, 해당 스레드의 실행이 끝날 때까지 대기합니다.
  • interrupt() : 스레드의 일시 정지 상태를 해제하고 중단시키는 메서드입니다.
  • yield() : 현재 실행 중인 스레드가 다른 스레드에게 실행을 양보하는 메서드입니다.
  • getName() : 스레드의 이름을 반환하는 메서드입니다.
  • getPriority() : 스레드의 우선순위를 반환하는 메서드입니다.

sleep 메서드 예제

public class Main {

	public static void main(String[] args) {
		Thread threadA = new Thread(new Runnable() {
			
			@Override
			public void run() {
				System.out.println("스레드 A 시작");
				try {
					long startTime = System.currentTimeMillis();
					Thread.sleep(1000);
					long endTime = System.currentTimeMillis();
					long millis = endTime - startTime;
                    // 출력 : 1008ms 지난 뒤에 스레드 A 끝
					System.out.println(millis + "ms 지난 뒤에 스레드 A 끝");
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		});
    }
}

join 메서드 예제

public class Main {

	public static void main(String[] args) {
		Thread threadA = new Thread(() -> {
			System.out.println("스레드 A 시작");
			try {
				Thread.sleep(1000);
				System.out.println("스레드 A 끝");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		});
		
		Thread threadB = new Thread(() -> {
			System.out.println("스레드 B 시작");
			System.out.println("스레드 B 끝");
		});
		
		threadA.start();
		threadB.start();
    }
}

출력 결과

스레드 A 시작
스레드 B 시작
스레드 B 끝
스레드 A 끝

위와 같이 출력이 됩니다. 스레드 A의 작업이 끝난 뒤에 B를 끝내고 싶으면 join 메서드를 사용하여 스레드 B에서 스레드 A의 작업이 끝날때까지 대기 후 진행하면 됩니다.

public class Main {

	public static void main(String[] args) {
		Thread threadA = new Thread(() -> {
			System.out.println("스레드 A 시작");
			try {
				Thread.sleep(1000);
				System.out.println("스레드 A 끝");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		});
		
		Thread threadB = new Thread(() -> {
			System.out.println("스레드 B 시작");
			try {
				threadA.join();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("스레드 B 끝");
		});
		
		threadA.start();
		threadB.start();
    }
}

출력 결과

스레드 A 시작
스레드 B 시작
스레드 A 끝
스레드 B 끝

interrupt 메서드 예제

public class Main {

	public static void main(String[] args) {
		Thread threadA = new Thread(() -> {
			try {
				for (int i = 0; i < 5; i++) {
					System.out.println("스레드 A "+ i +"작업 시작");
				
					Thread.sleep(1000);
					System.out.println("스레드 A "+ i +"작업 끝");
				} 
			}catch (InterruptedException e) {
				System.out.println("스레드 A 끝");
			}
			
		});
		
		threadA.start();
		
		try {
			Thread.sleep(2000);
			threadA.interrupt();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
    }
}

출력 결과

스레드 A 0작업 시작
스레드 A 0작업 끝
스레드 A 1작업 시작
스레드 A 끝

2000ms 뒤에 스레드 A interrupt 메서드를 수행합니다. 그러면 스레드 A 실행 코드 쪽에서 InterruptedException 예외에서 catch 후 스레드 A는 종료됩니다.

 

stop() 대신 interrupt()를 사용하는 이유

stop() 메서드는 스레드를 강제로 중지시키는 기능을 제공하지만, 이 메서드는 스레드를 갑작스럽게 중단시켜서 리소스 누수나 예상치 못한 상태로 프로그램을 끝낼 수 있습니다. 그래서 Deprecated되었습니다.

interrupt() 메서드는 스레드에게 인터럽트 신호를 보내어 스레드가 현재 작업을 중단하도록 유도하는 역할을 합니다.

 

Runnable 인터페이스

Runnable 인터페이스는 스레드를 구현하는 데 사용되는 인터페이스입니다. Runnable 인터페이스를 구현하여 스레드를 구현할 수 있습니다. run() 메서드를 구현하여 해당 스레드가 실행할 코드를 정의합니다.

 

Runnable 인터페이스 장점

  • 다중 상속이 불가능한 자바에서 여러 인터페이스를 구현하면서 스레드를 생성할 수 있습니다.