본문 바로가기
Java/기본 문법

쓰레드(Thread)

by 정구정구 2026. 6. 11.

쓰레드(Thread)

프로그램 내에서 독립적으로 실행되는 하나의 작업 단위

 

 

멀티 쓰레드(Multi-Thread) 구현

  • Thread 클래스를 상속받아 쓰레드 구현 가능
  • Thread.run() 메서드를 오버라이드 해서 쓰레드가 수행할 작업 정의 가능
  • start() 메서드로 새로운 쓰레드가 생성되고 run()으로 실행됨

ex) 쓰레드 2개가 각각 0~9까지 출력하는 멀티 쓰레드 프로그램

public class MyThread extends Thread{

    @Override
    public void run() {
        String threadName = Thread.currentThread().getName();
        System.out.println("::: " + threadName + "쓰레드 시작 :::");

        for (int i = 0; i < 10; i++) {
            System.out.println("현재 쓰레드: " + threadName + " - " + i);

            try {
                Thread.sleep(500);
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("::: " + threadName + "쓰레드 종료 :::");
    }
}
public class Main {
    public static void main(String[] args) {

        System.out.println("::: main 쓰레드 시작");

        MyThread thread0 = new MyThread();
        MyThread thread1 = new MyThread();

        System.out.println("::: main 이 thread0 을 실행");
        thread0.start();

        System.out.println("::: main 이 thread1 을 실행");
        thread1.start();
    }
}

 

 

*쓰레드 실행 시, run()을 사용하면 새로운 쓰레드에서 시작하는게 아니라 현재 쓰레드에서 실행된다.

 

 

 

Join()

  • main() 쓰레드가 다른 쓰레드가 종료될 때까지 기다리게 하는 메서드
  • 모든 작업이 끝난 뒤, 총 작업 완료 시간 측정하는데 유용하게 쓰임
public class Main {

    public static void main(String[] args) {
        System.out.println("::: main 쓰레드 시작");
        MyThread thread0 = new MyThread();
        MyThread thread1 = new MyThread();

        // 시작시간 기록
        long startTime = System.currentTimeMillis();

        // 1. thread0 시작
        System.out.println("thread0 시작");
        thread0.start();

        // 2. thread1 시작
        System.out.println("thread1 시작");
        thread1.start();

        // ⌛️ main 쓰레드 대기 시키기
        try {
            thread0.join();
            thread1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        long endTime = System.currentTimeMillis();
        long totalTime = endTime - startTime;
        System.out.println("총 작업 시간: " + totalTime + "ms");
        System.out.println("::: main 쓰레드 종료");
    }
}

 

 

 

Runnable 인터페이스 활용

Runnable 인터페이스를 활용해 쓰레드를 구현하는 것을 권장 

 

유지보수성과 재사용성 향상

  • Thread 클래스를 상속받아 MyThread()를 구현하면 MyThread()가 실행 로직과 쓰레드 제어 로직 모두를 담당하게 됨 (쓰레드 제어 로직 : start(), join(), isAlive() 등)
  • 하나의 클래스는 하나의 책임만을 가지는게 유지 보수에 좋음
  • Runnable을 활용하면 실행 로직을 별도의 구현체로 분리 가능
// MyThread에 있는 실행 로직만 그대로 복붙
public class MyRunnable implements Runnable {
    @Override
    public void run() {
        String threadName = Thread.currentThread().getName();
        for (int i = 0; i < 10; i++) {
            System.out.println("현재 쓰레드: " + threadName + " - " + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class Main {

    public static void main(String[] args) {

        // 쓰레드 실행 로직 객체 (작업 객체)
        MyRunnable task = new MyRunnable();

       // 쓰레드 제어를 위해 제공되는 Thread 클래스 
        Thread thread0 = new Thread(task); // 작업 객체 공유
        Thread thread1 = new Thread(task); // 작업 객체 공유

        // 실행
        thread0.start();
        thread1.start();
    }
}

 

 

기존 클래스를 유지하면서 확장 가능

  • MyThread()처럼 Thread를 상속하면 다른 클래스 상속 불가능 (Java는 클래스 다중 상속 불가능) -> 확장성이 떨어짐
  • Runnable은 인터페이스이므로 기존 클래스의 기능을 유지하면서 상속을 통해 확장 가능
public class MyNewClass { 

    public void printMessage() {
        System.out.println("MyClass 기능 실행");
    }
}
public class MyRunnable extends MyNewClass implements Runnable {

    @Override
    public void run() {
        String threadName = Thread.currentThread().getName();
        for (int i = 0; i < 10; i++) {
            System.out.println("현재 쓰레드: " + threadName + " - " + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class Main {

    public static void main(String[] args) {

        MyRunnable task = new MyRunnable();

        // 기존 클래스를 유지하면서 확장해서 활용
        task.printMessage(); 

        Thread thread0 = new Thread(task);
        Thread thread1 = new Thread(task);

        thread0.start();
        thread1.start();
    }
}

'Java > 기본 문법' 카테고리의 다른 글

Collection 주요 기능 - Map  (0) 2026.06.11
Collection 주요 기능 - List  (0) 2026.06.11
스트림(Stream)  (0) 2026.06.04
인터페이스(interface)  (0) 2026.06.04
람다(Lambda)  (0) 2026.05.21