스레드는 생성 → 시작 → 종료되는 생명주기를 가진다.

스레드 생명 주기

 

  • 일단 실행 가능한 상태가 되면, 일시 중지 상태로 바뀔 수 있다
    • 참고: 자바에서 스레드의 ‘일시 중지 상태’ 라는 것은 없다.
    • 스레드가 기다리는 상태를 묶어서 설명하기 위해 사용한 용어다.

5가지 상태가 있다는 정도만 알아두자. 뒤에서 자세히 다루기 때문이다.

 

1. New (생성만 된 상태)

  • Thread 객체가 생성되지만, start()메서드가 호출되지 않은 상태다.
  • 예: Thread thread = new Thread(runnable)

2. Runnable (실행 가능 상태)

  • 보통 실행 상태라고 부른다
  • start() 메서드가 호출되면, 스레드는 이 상태로 들어간다.
  • 이 상태에서 스레드는 실제로 CPU에서 실행될 수 있다. (이 상태에서만 CPU 스케쥴러에 들어가요!)
  • 운영체제의 스케쥴러가 각 스레드에 CPU 시간을 할당하여 실행하기 때문에, Runnable 상태에 있는 스레드는 스케쥴러의 실행 대기열에 포함되어 있다가 차례로 CPU에서 실행된다.
    • 즉, 운영체제 입장에서 보면, CPU가 실제로 실행하는 스레드와 OS 스케쥴링 큐에 대기한 스레드 둘 다 포함이다.

3. Blocked (차단 상태)

  • 동기화 락을 얻기 위해 기다리는 상태
  • 예를 들어, synchronized 블록에 진입하기 위해 을 얻어야하는 경우 이 상태에 들어간다.
    • 락은 스레드 하나만 가지고 있을 수 있다.

4. Waiting (대기 상태)

  • 스레드가 다른 스레드의 특정 작업이 완료되기를 무기한 기다리는 상태
  • 스레드는 다른 스레드가 notify(), notifyAll() 메서드를 호출하거나, join()이 완료될 때 까지 기다린다.
  • wait(), join() 메서드가 호출되면 이 상태가 된다.
  • 예: object.wait()

5. Timed Waiting (시간 제한 대기 상태)

  • 스레드가 특정 시간 동안만 대기하는 상태
  • 주어진 시간이 경과하거나, 다른 스레드가 해당 스레드를 깨우면 이 상태에서 벗어난다.
  • sleep(long millis), wait(long timeout), join(long millis) 메서드 호출 시 이 상태가 된다.
  • 예. Thread.sleep(1000);

6. Terminated (종료 상태)

  • 스레드 실행이 완료된 상태.
  • 스레드가 정상적으로 종료되거나 예외가 발생한 경우에 Terminated 가 된다.
  • 스레드가 종료되면 다시 시작할 수 없다.
728x90

'프로그래밍 > JAVA' 카테고리의 다른 글

synchronized  (0) 2025.04.03
volatile  (0) 2025.04.03
스레드 생성과 실행  (0) 2025.04.03
List  (0) 2025.03.28
스레드 생성하기  (0) 2025.03.28

 

HelloThread - 스레드 생성

스레드를 생성해보자.

클래스에 Thread 를 상속 받고 run 메서드를 재정의하면 된다!

public class HelloThread extends Thread {
  @Override
  public void run() {
      System.out.println(
      Thread.currentThread().getName() + " : run()");
	}
}

 

HelloThreadMain

  • 해당 코드를 실행하는 스레드 이름을 출력한다 Thread.currentThread().getName()
    • 그래서 메인 메서드를 실행하는 main 이라는 스레드명이 제일 처음에 출력된다.
    • 누가 이 코드를 실행하는지 스레드명을 확인하면서 학습하자.
public static void main(String[] args) {
  /** Thread.currentThread().getName() -> 스레드명이 main 이라고 출력된다 */
  System.out.println(Thread.currentThread().getName() + ": main() start");
  
  HelloThread helloThread = new HelloThread(); // HelloThread 객체를 생성
  System.out.println(Thread.currentThread().getName() + ": start() 호출 전 ");
  
  helloThread.start(); // start() 를 호출한다 ! 
  // 이 시점부터 main 스레드와 Thread-0 이 동시에 실행된다.
  
  System.out.println(Thread.currentThread().getName() + ": start() 호출 후 ");

  System.out.println(Thread.currentThread().getName() + ": main() end");
}
  • HelloThread 인스턴스를 생성하고 HelloThread helloThread = new HelloThread()
    • 이것은 인스턴스 생성만 됬을 뿐, 스택 프레임이 할당된 게 아니다.
  • start() 를 호출한다. helloThread.start()

 

중요 - 어느 시점에 새로운 스택 프레임이 생성될까 

  • helloThread.start() 를 호출하면, HelloThread 의 스택 프레임이 생성된다.
  • (main 스레드와는 별도의 스택 프레임이다)
  • 그리고 HelloThread 가 run() 를 호출한다.
  • 주의할 점은 main 스레드가 아니라, HelloThread 가 run() 을 호출한다는 점이다.
  • main 스레드는 단지 helloThread.start() 호출을 통해서 다른 스레드에게 일을 시작하라고 지시할 뿐이다.

 

스레드 간의 실행 순서와 실행 기간을 둘 다 보장하지 않는다.

  • 스레드는 동시에 실행되기 때문에 실행 순서는 얼마든지 달라질 수 있다.
main: main() start
main: start() 호출 전 
main: start() 호출 후 
Thread-0 : run()
main: main() end
  • 실행 할 때마다 조금 달라진다. Thread-0 이 제일 밑에 출력될 때도 있다
main: main() start
main: start() 호출 전 
main: start() 호출 후 
main: main() end
Thread-0 : run()

정리

  • 스레드 객체를 생성하고, 반드시 start() 를 호출해야 스택 공간을 할당 받고 스레드가 작동한다.
  • 스레드는 순서와 실행 기간을 모두 보장하지 않는다! 이것이 멀티스레드다.
728x90

'프로그래밍 > JAVA' 카테고리의 다른 글

volatile  (0) 2025.04.03
스레드 생명 주기  (0) 2025.04.03
List  (0) 2025.03.28
스레드 생성하기  (0) 2025.03.28
Exception  (0) 2025.03.20

HelloThread - 스레드 생성

스레드를 생성해보자.

클래스에 Thread 를 상속 받고 run 메서드를 재정의하면 된다!

public class HelloThread extends Thread {
  @Override
  public void run() {
      System.out.println(
      Thread.currentThread().getName() + " : run()");
	}
}

HelloThreadMain

  • 해당 코드를 실행하는 스레드 이름을 출력한다 Thread.currentThread().getName()
    • 그래서 메인 메서드를 실행하는 main 이라는 스레드명이 제일 처음에 출력된다.
    • 누가 이 코드를 실행하는지 스레드명을 확인하면서 학습하자.
public static void main(String[] args) {
  /** Thread.currentThread().getName() -> 스레드명이 main 이라고 출력된다 */
  System.out.println(Thread.currentThread().getName() + ": main() start");
  
  HelloThread helloThread = new HelloThread(); // HelloThread 객체를 생성
  System.out.println(Thread.currentThread().getName() + ": start() 호출 전 ");
  
  helloThread.start(); // start() 를 호출한다 ! 
  // 이 시점부터 main 스레드와 Thread-0 이 동시에 실행된다.
  
  System.out.println(Thread.currentThread().getName() + ": start() 호출 후 ");

  System.out.println(Thread.currentThread().getName() + ": main() end");
}
  • HelloThread 인스턴스를 생성하고 HelloThread helloThread = new HelloThread()
    • 인스턴스 생성만 됬을 뿐, 스택 프레임이 할당된 게 아니다.
  • start() 를 호출한다.

 

helloThread.start() 를 호출하면, HelloThread 의 스택 프레임이 생성된다.

(main 스레드와는 별도의 스택 프레임이다)

그리고 HelloThread 가 run() 를 호출한다.

주의할 점은 main 스레드가 아니라, HelloThread 가 run() 을 호출한다는 점이다.

main 스레드는 단지 helloThread.start() 호출을 통해서 다른 스레드에게 일을 시작하라고 지시할 뿐이다.

 

  • 스레드는 동시에 실행되기 때문에 실행 순서는 얼마든지 달라질 수 있다.
main: main() start
main: start() 호출 전 
main: start() 호출 후 
Thread-0 : run()
main: main() end
  • 실행 할 때마다 조금 달라진다. Thread-0 이 제일 밑에 출력될 때도 있다

정리 

  • 스레드 객체를 생성하고, 반드시 start() 를 호출해야 스택 공간을 할당 받고 스레드가 작동한다.
  • 스레드는 순서와 실행 기간을 모두 보장하지 않는다!

 

 

Runnable 인터페이스

  • 자바가 제공하는 스레드 실행용 인터페이스다.
public interface Runnable {
		void run();
}

어떻게 사용하는지 살펴보자.

HelloRunnable implements Runnable

public class HelloRunnable implements Runnable {
  @Override
  public void run() { // run() 내에 작업 로직을 구현한다 
      System.out.println(Thread.currentThread().getName() + ": run()");
  }
}

 

HelloRunnableMain

  • 실행 결과는 기존과 같다.
  • 차이가 있다면, Thread 와 해당 스레드가 실행할 작업이 분리되어 있다는 점이다.
  • Thread 객체를 생성할 때, 생성자로 작업 클래스를 전달한다.
public class HelloRunnableMain {
  public static void main(String[] args) {
    System.out.println(Thread.currentThread().getName() + ": main() start");

    HelloRunnable runnable = new HelloRunnable(); // 작업 정의
    Thread thread = new Thread(runnable); // 스레드
    thread.start();

    System.out.println(Thread.currentThread().getName() + ": main() end");
  }
}

 

Runnable 인터페이스 구현하는 방식이 더 나은 이유!

Thread 클래스 상속 방식의 단점

  • 자바는 단일 상속만을 허용하므로, Thread 클래스를 상속받으면, 다른 클래스를 상속받을 수 없다.
  • 인터페이스를 사용하는 방식에 비해 유연성이 떨어진다.

Runnable 인터페이스를 구현하는 방식

  • 상속의 자유로움
  • 코드의 분리: 스레드와 실행할 작업은 분리하여 코드의 가독성을 높일 수 있다.
  • 여러 스레드가 동일한 Runnable 객체를 공유할 수 있어 자원 관리를 효율적으로 할 수 있다!
728x90

'프로그래밍 > JAVA' 카테고리의 다른 글

스레드 생성과 실행  (0) 2025.04.03
List  (0) 2025.03.28
Exception  (0) 2025.03.20
String 클래스  (1) 2025.03.20
자바 객체 지향  (0) 2025.03.13

+ Recent posts