[Java] 멀티 스레드 ①

kiteB·2022년 2월 9일
1

Java2

목록 보기
1/36
post-thumbnail

[ 멀티 스레드 개념 ]

1. 프로세스와 스레드

📌 프로세스( precess )란?

  • 운영체제에서는 실행 중인 하나의 애플리케이션을 프로세스라고 부른다.
  • 즉, 사용자가 작성한 프로그램이 운영체제에 의해 메모리 공간을 할당받아 실행 중인 것을 말한다.
  • 하나의 애플리케이션은 다중 프로세스를 만들기도 한다.
  • 이러한 프로세스는 프로그램에 사용되는 데이터와 메모리 등의 자원, 그리고 스레드로 구성된다.

📌 스레드( thread )란?

  • 프로세스 내에서 실제로 작업을 수행하는 주체를 뜻한다.
  • 모든 프로세스는 한 개 이상의 스레드가 존재하여 작업을 수행한다.
    • 두 개 이상의 스레드를 가지는 프로세스를 멀티스레드 프로세스(multi-threaded process)라고 부른다.

📌 멀티 태스킹( multi tasking )이란?

  • 두 가지 이상의 작업을 동시에 처리하는 것을 의미한다.
  • 운영체제는 멀티 태스킹을 할 수 있도록 CPU 및 메모리 자원을 프로세스마다 적절히 할당해주고, 병렬로 실행시킨다.
  • 멀티 태스킹은 꼭 멀티 프로세스를 의미하지는 않는다.

📌 멀티 프로세스 ( multi process ) vs 멀티 스레드( multi thread )

여러 흐름을 동시에 수행한다는 공통점을 가지고 있다.

  • 멀티 프로세스: 여러 개의 CPU를 사용하여 여러 프로세스를 동시에 수행하는 것
    • 각 프로세스가 독립적인 메모리를 가지고 별도로 실행된다.
      • 하나의 프로세스에서 오류가 발생해도 다른 프로세스에 영향을 미치지 않는다.
        (1개의 프로세스가 죽어도 다른 프로세스들은 계속 실행된다.)
      • Context Switching을 위한 오버헤드가 발생한다.
  • 멀티 스레드: 하나의 프로세스 내에서 둘 이상의 스레드가 동시에 작업을 수행하는 것
    • 각 스레드가 자신이 속한 프로세스의 메모리를 공유한다.
      • 시스템 자원 낭비가 적다.
      • 하나의 스레드에 문제가 생기면, 전체 프로세스가 영향을 받는다.

2. 메인 스레드 ( main thread )

모든 자바 애플리케이션은 메인 스레드가 main() 메소드를 실행하면서 시작된다.

메인 스레드는 main() 메소드의 첫 코드부터 아래로 순차적으로 실행하고,
main() 메소드의 마지막 코드를 실행하거나 return 문을 만나면 실행이 종료된다.

메인 스레드는 필요에 따라 작업 스레드들을 만들어서 병렬로 코드를 실행할 수 있다.
멀티 스레드를 생성해서 멀티 태스킹을 수행한다.

  • 싱글 스레드 애플리케이션: 메인 스레드가 종료하면 프로세스도 종료된다.
  • 멀티 스레드 애플리케이션: 실행 중인 스레드가 하나라도 있다면, 프로세스는 종료되지 않는다. 메인 스레드가 작업 스레드보다 먼저 종료되더라도 작업 스레드가 계속 실행 중이라면 프로세스는 종료되지 않는다.

[ 작업 스레드 생성과 실행 ]

멀티 스레드로 실행하는 애플리케이션을 개발하려면 먼저 몇 개의 작업을 병렬로 실행할지 결정하고 각 작업별로 스레드를 생성해야 한다.

어떤 자바 애플리케이션이건 메인 스레드는 반드시 존재하기 때문에 메인 작업 이외에 추가적인 병렬 작업의 수만큼 스레드를 생성하면 된다.

자바에서 스레드를 생성하는 방법은 두 가지 방법이 있다. 참고로 자바에서는 작업 스레드도 객체로 생성되기 때문에 클래스가 필요하다.

  • java.lang.Thread 클래스를 직접 객체화해서 생성하는 방법
  • Thread를 상속해서 하위 클래스를 만들어 생성하는 방법

1. Thread 클래스로부터 직접 실행

java.lang.Thread 클래스로부터 작업 스레드 객체를 직접 생성하려면 Runnable을 매개값으로 갖는 생성자를 호출해야 한다.

Thread thread = new Thread(Runnable target);

Runnable 인터페이스란?

Runnable 인터페이스는 몸체가 없는 메소드인 run() 메소드 단 하나만을 갖는 간단한 인터페이스로, 작업 스레드가 실행할 수 있는 코드를 가지고 있는 객체라고 해서 붙여진 이름이다.

public interface Runnable {
    public abstract void run();
}

Runnable은 인터페이스 타입이기 때문에 구현 객체가 필요하다.
구현 클래스는 run()을 재정의해서 작업 스레드가 실행할 코드를 작성해야 한다.

class Task implements Runnable {
    public void run() {
        //스레드가 실행할 코드;
    }
}

Thread 생성

Runnable은 작업 내용을 가지고 있는 객체이지, 실제 스레드는 아니다.

1. 기본 형태

Runnable 구현 객체를 생성한 후, 이를 매개값으로 Thread 생성자를 호출해야 작업 스레드가 생성된다.

Runnable task = new Task();
Thread thread = new Thread(task);

2. 익명 객체 사용

코드 절약을 위해 Thread 생성자를 호출할 때 Runnable 익명 객체를 매개값으로 사용할 수 있다. (많이 사용되는 방식)

Thread thread = new Thread(new Runnable() {
    public void run() {
        //스레드가 실행할 코드;
    }
});

3. 람다식 사용

Runnable 인터페이스는 함수적 인터페이스이기 때문에 람다식을 매개값으로 사용할 수도 있다.

  • 함수적 인터페이스: 추상메소드가 1개만 정의된 인터페이스
  • 자바 8부터 지원되기 때문에 자바 7 이전 버전에서는 사용할 수 없다.
Thread thread = new Thread(() -> {
    //스레드가 실행할 코드;
});

Thread 실행

작업 스레드는 start() 메소드를 호출해야만 비로소 실행된다. (생성되는 즉시 실행되는 것이 아니다!)

thread.start();

start() 메소드가 호출되면, 작업 스레드는 매개값으로 받은 Runnablerun() 메소드를 실행하면서 자신의 작업을 처리한다.


2. Thread 하위 클래스로부터 생성

작업 스레드가 실행할 작업을 Runnable로 만들지 않고, Thread의 하위 클래스로 작업 스레드를 정의하면서 작업 내용을 포함시킬 수도 있다.

✅ 작업 Thread 클래스 정의 방법

1. 기본 형태

  • Thread 클래스를 상속한 후 run 메소드를 재정의(overriding)해서 스레드가 실행할 코드를 작성한다.
  • 작업 스레드 클래스로부터 작업 스레드 객체를 생성하는 방법은 일반적인 객체를 생성하는 방법과 동일하다.
public class WorkerThread extends Thread {
    @Override
    public void run() {
        //스레드가 실행할 코드 
    }
}
Thread thread = new WorkerThread();

2. 익명 객체 이용

코드 절약을 위해 Thread 익명 객체로 작업 스레드 객체를 생성할 수도 있다.

Thread thread = new Thread() {
    public void run() {
        //스레드가 실행할 코드;
    }
}

Thread 실행

이렇게 생성된 작업 스레드 객체에서 start() 메소드를 호출하면 작업 스레드는 자신의 run() 메소드를 실행하게 된다.

thread.start();

3. 스레드의 이름

스레드는 자신의 이름을 가지고 있다. 스레드의 이름이 큰 역할을 하는 것은 아니지만,
디버깅할 때 어떤 스레드가 어떤 작업을 하는지 조사할 목적으로 가끔 사용된다.

  • 메인 스레드는 main이라는 이름을 가지고 있고,
  • 우리가 직접 생성한 스레드는 자동적으로 Thread-n이라는 이름으로 설정된다. (n: 스레드의 번호)
    • Thread-n 대신 다른 이름으로 설정하고 싶다면 Thread 클래스의 setName() 메소드로 변경하면 된다.

Thread 이름 관련 메소드 정리

  • 스레드 이름 설정하기
thread.setName("스레드 이름");
  • 스레드 이름 알아내기
thread.getName();

setName()getName()Thread의 인스턴스 메소드이므로 스레드 객체의 참조가 필요하다. 만약 스레드 객체의 참조를 가지고 있지 않다면, Thread의 정적 메소드인 currentThread()로 코드를 실행하는 현재 스레드의 참조를 얻을 수 있다.

Thread thread = Thread.currentThread();

[ 참고자료 ]

이것이 자바다 책
http://tcpschool.com/java/java_thread_concept
https://makecodework.tistory.com/entry/Java-%EB%9E%8C%EB%8B%A4%EC%8B%9DLambda-%EC%9D%B5%ED%9E%88%EA%B8%B0
https://mangkyu.tistory.com/92

profile
🚧 https://coji.tistory.com/ 🏠

0개의 댓글