JAVA,Spring

[멀티스레드와 동시성] - 스레드(Thread)

devkdh 2025. 9. 18. 20:43

스레드란?

스레드란 하나의 프로세스에서 동시에 실행될 수 있는 독립적인 실행 흐름 단위이다.
자바 어플리케이션은 기본적으로 하나의 메인 스레드로 실행되지만 여러개의 스레드를 생성하면 동시실행이 가능하다.

사용법

Thread 클래스를 상속하거나, Runnable 인터페이스를 구현한 후, start()매소드를 호출해서 실행할 수 있다.

Tread 클래스 상속

Thread 클래스를 상속받고, run() 매소드를 오버라이드 하는 방식

class GetMessage extends Thread{
    @Override
    public void run(){
        System.out.println("메시지 수신 스레드 실행 중: "+ Thread.currentThread().getName());
    }
}
public class Main {
    public static void main(String[] args) {
        GetMessage getMessage = new GetMessage();
        getMessage.start();
    }
}

실행 결과

메시지 수신 스레드 실행 중: Thread-0

이때 start() 매소드가 아닌 run()매소드를 호출하면 현재 스레드에서 실행된다.
start()매소드를 호출해야 새로운 스레드를 만든다.

start()는 OS 시스템 콜을 통해 실제 스레드를 생성하고, 그 스레드에서 run()을 실행한다.

아래 코드는 이를 보여주는 예시이다.



class Test extends Thread{
    @Override
    public void run(){
        System.out.println("테스트 스레드 실행 중: "+ Thread.currentThread().getName());
    }
}
public class Main {
    public static void main(String[] args) {
        Test useRun = new Test();
        Test useStart = new Test();
        System.out.println("run() 매소드 사용");
        useRun.run();
        useStart.run();
        System.out.println("start() 매소드 사용");
        useRun.start();
        useStart.start();
    }
}

실행 결과

run() 매소드 사용
테스트 스레드 실행 중: main
테스트 스레드 실행 중: main
start() 매소드 사용
테스트 스레드 실행 중: Thread-0
테스트 스레드 실행 중: Thread-1

## Runnable 인터페이스 구현하기


class Task implements Runnable{
    @Override
    public void run(){
        System.out.println("작업 실행 중: " + Thread.currentThread().getName());
    }


}

public class Main {
    public static void main(String[] args) {
        Runnable task = new Task();
        Thread thread = new Thread(task);
        thread.start();
    }
}

실행결과

작업 실행 중: Thread-0

스레드의 예외처리

스레드 내부에서 예외가 발생하면 그 스레드는 종료되고 예외가 발생했다는 사실조차 알 수 없다.
따라서 반드시 명시적인 예외처리가 필요하다.



class Test extends Thread{
    @Override
    public void run(){
        System.out.println("테스트 스레드 실행 중: "+ Thread.currentThread().getName());
        throw new RuntimeException("에러 발생!!");
    }
}
public class Main {
    public static void main(String[] args) {
        Test test = new Test();
        test.start();
        System.out.println("메인 스레드는 죽지 않는다.");
    }
}

실행 결과

메인 스레드는 죽지 않는다.
테스트 스레드 실행 중: Thread-0
Exception in thread "Thread-0" java.lang.RuntimeException: 에러 발생!!
    at Test.run(Main.java:7)

종료 코드 0(으)로 완료된 프로세스

Thread-0 이 에러를 뱉어도 메인스레드는 종료되지 않고 실행되는 모습이다.

그럼 main스레드에서 이를 알려면 어떻게 해야할까?

스레드 내부에서 try-catch 로 직접 예외 감싸기



class Test extends Thread{
    @Override
    public void run(){
        try{
            System.out.println("테스트 스레드 실행 중: "+ Thread.currentThread().getName());
            throw new RuntimeException("에러 발생!!");
        }catch (Exception e){
            System.out.println("예외 처리: "+ e.getMessage());
        }

    }
}
public class Main {
    public static void main(String[] args) {
        Test test = new Test();
        test.start();
        System.out.println("메인 스레드는 죽지 않는다.");
    }
}

실행 결과

메인 스레드는 죽지 않는다.
테스트 스레드 실행 중: Thread-0
예외 처리: 에러 발생!!

예외처리가 내부적으로 되기에 스레드가 죽지않고 정상적으로 종료된다.

UncaughtExceptionHandler 등록



class Test extends Thread{
    public Test(){
        setUncaughtExceptionHandler((t,e)->{
            System.out.println("[" + t.getName() + "] 예외 발생: " + e.getMessage());
        });
    }
    @Override
    public void run(){
        throw new RuntimeException("에러 발생!!");
    }
}
public class Main {
    public static void main(String[] args) {
        Test test = new Test();
        test.start();
        System.out.println("메인 스레드는 죽지 않는다.");
    }
}

실행 결과

메인 스레드는 죽지 않는다.
[Thread-0] 예외 발생: 에러 발생!!

종료 코드 0(으)로 완료된 프로세스

이 경우 스레드는 죽지만 해당 스레드를 핸들러가 감지해서 예외처리를 할 수 있다.