(JAVA) 스레드 생성과 실행

Yangray·2025년 4월 3일

JAVA

목록 보기
1/3

[출처] 김영한 자바-고급 1편 멀티스레드와 동시성

💥 JVM 구조

✔ Method Area

: 프로그램을 실행하는데 필요한 공통 데이터 관리, 프로그램의 모든 영역에서 공유

  • 클래스 정보 : 클래스의 실행 코드(바이트 코드), 필드, 메서드와 생성자 코드 등 모든 실행 코드가 존재
  • static 영역 : static 변수들을 보관
  • 런타임 상수 풀 : 프로그램을 실행하는데 필요한 공통 리터럴 상수를 보관

✔ Stack Area

: 자바가 실행이 되면 하나의 스택이 생성 되는데, 각 프레임마다 지역 변수, 중간 연산 결과, 메서드 호출 정보 등을 포함한다.

  • 스택 프레임 : 스택 영역에 쌓이는 하나의 공간이 스택 프래임이다. 메서드를 호출할 때 마다 하나의 스택 프레임이 쌓이고, 종료되면 해당 스택 프레임이 제거된다.

✔ Heap Area

: 객체(인스턴스)와 배열이 생성되는 영역이다. 가비지 컬렉션이 이루어지는 주요 영역이며, 더 이상 참조되지 않는 객체는 가비지 컬렉션에 의해 제거된다.

😃 스택 영역은 각 스레드별로 하나의 실행 스택이 생성되고 스레드 수가 추가되면 스택도 스레드 수 만큼 증가한다!

💥 스레드 생성

✔ Thread 상속

  • Thread 클래스를 상속받고, 스레드 실행할 코드를 run 메서드에 재정의한다.
public class HelloThread extends Thread{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + ": run()"); // 실행 중인 스레드의 이름을 조회
    }
}

public class HelloThreadMain {
    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName() + " main() start");

        HelloThread helloThread = new HelloThread();
        System.out.println(Thread.currentThread().getName() + " : start() 호출 전");
        //helloThread.start();// 스레드를 호출
        helloThread.run();//run 직접 실행
        System.out.println(Thread.currentThread().getName() + " : start() 호출 후");

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

  • 스레드 생성 후 start 메서드 호출하면 별도의 스택 공간 할당 시킴
  • 새로 생성된 Thread-0 스레드에서 run 메서드 호출
  • 💥주의! main 메서드에서 start 메서드가 아닌 run 메서드를 바로 호출 시키면 생성된 스레드가 run 메서드를 실행하는 것이 아니라 main 스레드가 HelloThread 인스턴스에 있는 run 메서드를 실행시킴 결과적으로 Thread-0에서 처리하는게 아닌 main 스레드에서 모든 것이 처리된다
  • 따라서 main 스레드가 아닌 생성된 스레드에서 실행하려면, 반드시 start 메서드를 호출해야 한다.
main: main() start
main: run() 호출 전
main: run() 호출 후
main: main() end
Thread-0: run()

// main 스레드가 start 메서드 호출 후
// 별도의 스레드 Thread-0 스레드에서 run 메서드 실행 결과


main: main() start
main: run() 호출 전
main: run()
main: run() 호출 후
main: main() end

// main 메서드에서 run 메서드 실행 결과

참고로 스레드 간의 순서는 CPU가 결정하기 때문에 스레드는 순서와 실행 기간 모두 보장하지 않는다. (멀티스레드)

데몬스레드
  • 백그라운드에서 보조적인 작업 수행
  • JVM은 데몬 스레드의 실행 완료를 기다리지 않고 모든 데몬 스레드가 아닌 사용자 스레드가 종료되면 데몬 스레드는 자동 종료된다.
  • setDaemon(true)로 데몬 스레드 설정, start 메서드 실행 전에 설정해야함. 기본값은 false

✔ Runnable 인터페이스 구현

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

public class HellowRunnabelMain {
    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName() +" : main() start");

        HellowRunnable runnable = new HellowRunnable();

        Thread thread = new Thread(runnable);
        thread.start();

        System.out.println(Thread.currentThread().getName() +" : main() end");
    }
}
  • 실행 결과는 Thread 클래스 상속하는 방식과 동일
  • 스레드와 해당 스레드 작업이 서로 분리되어 있다는 점이 다름

Thread 상속 방식 보다는 Runnable 인터페이스 구현 방식 선호
-- 코드는 간단하지만, 자바는 단일 상속만 허용하기 때문에 이미 다른 클래스를 상속 받고 있는 경우 Thread 클래스를 상속 받을 수 없기 때문에 인터페이스 구현 방식보다 유연성이 떨어진다.
-- Runnable 인터페이스 방식은 스레드와 실행 작업을 명확히 분리할 수 있기 때문에 코드 가독성이 훨씬 뛰어나고 유연성이 좋아 유지보수가 편해지기 때문!

Runnable 만드는 다양한 방법

  1. 특정 클래스 안에서만 사용되는 경우 중첩 클래스 이용
  2. 특정 메서드 안에서만 간단하게 정의하고 사용되는 경우 익명 클래스 이용
  3. 람다를 이용
profile
시작은 미약하나 그 끝은 창대하리라

0개의 댓글