📘 Backend/Concurrency

Create Thread - Implementation Runnable & Thread

신건우 2023. 10. 2. 13:45

📘 Thread Creation with Runnable

Runnable 인터페이스를 구현해 Multi-Threading을 구현합니다.

아래 예시 코드의 new Thread(() -> {}) 람다 부분은 내부적으로 new Runnable()로 구성됩니다.


📌 start() & sleep()

아래 코드를 실행시켜 보면, 당연히 처음 로그는 main 스레드에서 생성했으니 이름이 main 입니다.

그 후, thread.start()를 거친 후의 thread name은 운영체제에서 스케줄링 되지 않았습니다.


왜냐하면 sleep으로 인해 운영체제가 비동기적으로 sleep을 실행했고,

그래서 2번쨰 스레드의 이름이 테스트-1이 아닌 main이 나오게 됩니다.

그리고 마지막으로 새 스레드의 코드가 실행되어 테스트-1 이라는 이름의 스레드가 반환되었습니다.


📌 setName() & setPriority()

그리고, Thread에 이름을 넣어주지 않으면 Thread-1 형식의 이름이 나오게 됩니다.

이름을 넣어주고 우선순위를 설정해 줌으로써 디버깅 등에 용이 하므로 항상 이름을 붙여주는게 좋습니다.

@Slf4j  
public class ImplementRunnable {  

        /* Implement Runnable */
    public static void create() throws InterruptedException {  
        // Thread()안의 파라미터는 내부적으로 new Runnable()로 실행됩니다.  
        Thread thread = new Thread(() -> {  
            // 어떤 코드를 넣던 운영 체제가 스케줄링 하자마자 새로운 스레드로 실행됩니다.  
            log.info("Thread 이름 : {}", Thread.currentThread().getName());  
            log.info("{} Thread's Priority : {}", Thread.currentThread().getName(), Thread.currentThread().getPriority());  
        });  

        // Thread Naming & Set Priority  
        thread.setName("테스트-1");  
        thread.setPriority(Thread.MAX_PRIORITY);  

        // 실행  
        log.info("실행 전 Thread 이름 : {}", Thread.currentThread().getName());  
        thread.start();  
        log.info("실행 후 Thread 이름 : {}", Thread.currentThread().getName());  

        // InterruptedException - Sleep는 반복되는 명령이 아닙니다.  
        Thread.sleep(10000);  
    }  

    public static void main(String[] args) {  
        try {  
            create();  
        } catch (InterruptedException e) {  
            throw new RuntimeException(e);  
        }  
    }  
}

출력값

> Task :ImplementRunnable.main()
01:30:29.555 [main] INFO com.thread.create.ImplementRunnable -- 실행 전 Thread 이름 : main
01:30:29.559 [main] INFO com.thread.create.ImplementRunnable -- 실행 후 Thread 이름 : main
01:30:29.559 [테스트-1] INFO com.thread.create.ImplementRunnable -- Thread 이름 : 테스트-1
01:30:29.559 [테스트-1] INFO com.thread.create.ImplementRunnable -- 테스트-1 Thread's Priority : 10

📘 Thread Class Capabilities

보통 Java에서 Unchecked Exception은 개발자가 직접 Catch 해서 처리하지 않으면 전체 스레드를 다운시킵니다.

이런 상황을 방지하기 위해 처음부터 전체 스레드에 해당하는 Exception Handler를 지정할 수 있습니다.

thread.setUncaughtExceptionHandler((t, e) -> {})람다는 내부적으로 new Thread.UncaughtExceptionHandler() 으로 구성됩니다.


Thread 내에서 발생한 예외가 어디에서도 Catch 되지 않으면 핸들러가 호출됩니다.

그럼 개발자는 Catch 되지 않은 스레드와 Exception을 출력하고 추가 데이터를 로깅하기만 하면 됩니다.

@Slf4j  
public class ImplementRunnable {  

    /* 캐치되지 않은 Exception Handler */    public static void handler() {  
        Thread thread = new Thread(() -> {  
            // 고의적으로 예외 발생  
            throw new RuntimeException("예외 처리 테스트");  
        });  

        thread.setName("예외-테스트");  
        thread.setUncaughtExceptionHandler((t, e) ->  {  
            log.info("{} Thread 내부에 치명적인 에러 발생, 에러 메시지 : {}", Thread.currentThread().getName(), e.getMessage());  
        });  
        thread.start();  
    }  

    public static void main(String[] args) {  
        handler();  
    }  
}

출력값

01:50:58.746 [예외-테스트] INFO com.thread.create.ImplementRunnable -- 예외-테스트 Thread 내부에 치명적인 에러 발생, 에러 메시지 : 예외 처리 테스트

📘 Thread를 확장한 Class

Runnable을 직접 구현하지 않고 Runnable을 구현한 Thread를 상속받아 확장한 Class로 스레드를 생성합니다.

이렇게 스레드를 생성하면 현재 스레드와 직접적으로 관련된 많은 데이터/메서드를 사용할 수 있습니다.


Runnable을 직접 구현한 Thread의 경우, Thread 인스턴스에 접근하려면 Thread.getCurrentThread()를 호출해야 했습니다.

하지만, Thread를 확장하면 this로 매우 많은 정보와 메서드에 접근이 가능하게 됩니다.

@Slf4j  
public class ImplementRunnable {

    /* Thread를 확장한 Thread */
    public static void extendedThread() {  
    Thread thread = new ExtendedThread();  
    thread.setName("Extend-1");  
    thread.start();  
    }

    /* Thread를 확장한 Private Class */
    private static class ExtendedThread extends Thread {  
    @Override  
    public void run() {  
        log.info("Thread를 확장한 Class의 Thread 이름 : {}" , this.getName());  
    }  
    }

  public static void main(String[] args) {   
        extendedThread();
  }
}

출력값

02:08:36.073 [Extend-1] INFO com.thread.create.ImplementRunnable -- Thread를 확장한 Class의 Thread 이름 : Extend-1