ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java] Thread에 대해 알아보자
    JAVA 2025. 6. 26. 18:29
    728x90
    반응형

    Java에서 Thread는 어플리케이션에서 실행되는 가장 작은 단위의 작업 흐름을 의미합니다.

    하나의 Process는 N개의 Thread를 가질 수 있으며 N개의 Thread가 동시에 실행되는 환경을 Multi-Thread라고 합니다.

    Java는 대표적인 Multi-Thread 환경이며 여러 작업을 병렬 처리하여 자원을 효율적으로 사용할 수 있는 장점이 있지만 동기화 문제와 교착 (Dead Lock) 상태 같은 문제들을 발생 할 수 있습니다.

    Thread 종류

    Java Thread는 크게 동작 방식과 역할에 따라 2가지로 분류할 수있습니다.

    1. User Thread

    백그라운드에서 동작하며 주요 로직을 수행하는 스레드를 의미합니다.

    • JVM은 모든 User Thread가 종료될 때까지 기다렸다가 종료됩니다.
    • 하나라도 남아있다면 JVM은 강제로 종료되지 않습니다.
    • 일반적으로 생성하는 스레드는 대부분 User Thread입니다.
    • 대표적으로 Java의 main()을 실행하는 Main Thread가 있습니다.
    • 아래에서 알아보는 것들은 모두 User Thread에 속합니다.

    2. Daemon Thread

    백그라운드에서 동작하며 주 Thread의 작업을 보조하는 역할을 합니다.

    • User Thread가 없다면 Daemon Thread가 실행 중이여도 강제 종료 됩니다.
    • Daemon Thread는 User Thread의 생명주기에 종속됩니다.
    • setDaemon(true)를 호출하여 설정할 수 있으며 Thread 시작되기 전에 설정해야 합니다.
    • 대표적으로 GC (Garbage Collector)가 있습니다.
    public static void main(String[] args) {
        Thread userThread = new Thread(() -> {
            ....
        });
        
        Thread daemonThread = new Thread(() -> {
            while(true) { ... }
        });
        
        daemonThread.setDaemon(true);
        userThread.start();
        daemonThread.start(); // while(true) 무한 루프지만 userThread 종료 시 종료 된다.
    }

    Thread 생성 방법

    Java에서 Thread를 생성하는 방법은 크게 2가지로 나눌 수 있습니다.

    1. 상속

    Java.lang.Thread 클래스를 상속받아서 run() 메소드를 @override하여 스레드가 수행할 작업을 구현할 수있습니다.

    이 방식의 간단하지만 Java의 경우 단일 상속만 지원하기 때문에 다른 클래스를 상속 받을 수 없습니다.

    public class Test extends Thread {
        @Override
        public void run() {
            ....
        }
    }
    
    public class TestEx {
        public static void main(String[] args) {
            Test t1 = new Test();
            t1.setName("Thread-1");
            t1.start();
            
            Test t2 = new Test();
            t2.run();
        }
    }

    run( )과 start( ) 차이점

    • run()을 호출하게 되면 현재 Thread에서 일반 메소드처럼 실행하게 됩니다.
    • start()를 호출하게 되면 JVM은 새로운 Thread를 생성하고 이 Thread 내부에서 run()을 호출하게 됩니다.

    2. 구현

    java.lang.Runnable 인터페이스를 구현하는 클래스를 정의하여 run()을 @override하여 스레드가 수행할 작업을 구현할 수있습니다.

    이 방식은 다중 인터페이스 구현이 가능하기 때문에 다른 클래스 상속과 다양한 인터페이스를 동시에 구현할 수 있기 때문에 권장되는 방식입니다.

    public class Test implements Runnable {
        @Override
        public void run() {
            ....   
        }
    }
    
    public class TestEx {
        public static void main(String[] args) {
        	// 일반 표현식
            Test t1 = new Test();
            Thread thread1 = new Thread(t1);
            thread1.start();
            
            // 람다 표현식
            Thread thread2 = new Thread(() -> {
                ....
            });
            thread2.start();
            
            // 이름 생략 & 람다 표현식
            new Thread(() -> {
                ....
            }).start();
        }
    }

    Thread 생명 주기 (Life Cycle)

    Java Thread는 6가지의 상태를 가질 수 있으며 Thread.getState()를 통해 현재 상태를 확인할 수 있습니다.

    https://www.baeldung.com/java-thread-lifecycle

    1. NEW : new Thread()를 통해 Thread 객체가 생성되었지만 아직 start() 호출하지 않은 단계입니다.
    2. Runnable : start() 호출하여 JVM 스케줄러에 의해 실행 준비가 되었거나 실행 중이지만 리소스 할당을 기다리는 단계입니다.
    3. Blocked : 동기화된 블록 or 메소드에 들어가거나 다시 들어가기 위해 모니터 잠금을 획득할 때까지 기다리는 단계입니다.
    4. Waiting : 시간 제한 없이 다른 Thread가 특정 작업을 완료될때까지 대기하는 단계입니다.
      1. Object.wait()
      2. Thread.join()
      3. LockSupport.park()
      4. 다른 Thread가 notify(), notifyAll()을 호출하면 기다리는 것을 멈출 수 있습니다.
    5. Timed Waiting : Thread가 지정된 시간 동안 다른 Thread의 작업이 완료되기를 대기하는 단계입니다.
      1. Object.wait(long timeout)
      2. Thread.sleep(long millis)
      3. Thread.join(long millis)
      4. LockSupport.parkNanos()
      5. LockSupport.parkUntil()
    6. Terminated : run() 호출 후 완료했거나 예외 발생 등으로 인해 스레드가 종료된 상태입니다.
    7. 🎉Suspended : Thread가 일시적으로 중단되었으며 다른 스레드에서 다시 시작 할 수 있는 단계입니다.
    728x90
    반응형
Designed by Tistory.