하나의 프로세스 내에서 실행되는 흐름의 단위를 말한다. 한 프로그램은 하나의 스레드를 가지고 있고, 둘 이상의 스레드를 동시에 실행하는 경우 이 방식을 멀티스레드라고 한다.
ex. 게임할 때 움직이면서 총을 쏘고 싶다. 한번 움직이고 총을 쏘면 효율이 없다. 총을 쏘면서 움직이도록 구현하기 위해 멀티 스레드를 이용하여 많은 양을 한번에 처리하도록 한다.
+) 프로세스란?
프로세스란 실행중인 프로그램을 말한다. 프로그램은 기억장치(SSD)에 존재하며 실행되기를 기다리는 명령어와 정적인 데이터 묶음이다. 이 프로그램을 명령어와 정적 데이터로 메모리에 적재시키면 생명이 있는 프로세스가 된다.
++) Process와 Thread의 차이는 무엇인가?
프로세스는 운영체제로부터 자원을 할당받는 작업 단위이다. 애플리케이션이 하나의 프로세스가 되고, 그 안에서 여러 개의 스레드가 할당 받은 자원을 이용하여 실행 단위로 존재할 수 있다. 즉 스레드는 하나의 프로세스 안에서 여러 실행의 흐름이라고 생각하면 된다.
자바는 JVM이라는 가상머신에 의해 동작한다. JVM은 운영체제의 역할을 하여, 자바에서 스레드는 JVM에 의해 스케쥴되는 실행 단위 코드 블록이다. JVM에 의해 하나의 프로세스가 발생하는 것이고, main() 안의 실행문들이 하나의 스레드가 된다. 만약 main() 이외의 스레드를 만들려면 Thread 클래스를 상속한다.
JVM은 스레드와 관련된 다음의 정보들을 관리한다.
즉, 개발자는 자바 스레드로 작동할 스레드 코드를 작성하며, 스레드 코드가 실행을 시작하도록 JVM에 요청한다. 그러면 JVM은 위의 정보들을 가지고 스레드를 실행시키는 것이다.
하나의 프로세스 내에서 여러 스레드를 동시에 실행시키는 방법을 말한다. 웹 서버는 대표적인 멀티 스레드 응용 프로그램이다.
하나의 스레드를 사용하여 단일 요청하기
요청이 오면, 쓰레드를 할당하고 쓰레드는 서블릿을 호출하고 서블릿을 작을 후 결과물을 http 응답에 담아 웹에 전달한다.
하나의 스레드를 사용하여 다중 요청하기
프로세스는 순서대로 요청을 처리한다.
이 문제를 해결하려면 요청마다 스레드를 생성하는 방법이 있다.
물론 요청마다 스레드를 생성하는 것은 장단점이 있다. 장점은 위의 예시처럼 동시 요청 처리가 가능하다. 다만 스레드 생성 비용은 비싸기 때문에 요청마다 스레드를 생성하면 컨텍스트 스위칭 비용이 발생하여 응답 속도가 느려질 것이다.
이를 극복할 수 있는 방법이 바로 스레드 풀이다! 우선 오늘은 이런 것이 있구나 라고만 잡고 스레드 풀에 대해서는 다음에 더 알아보겠다.
New(객체 생성)
스레드가 만들어진 상태로 아직 start() 메서드가 호출되지 않은 상태이다.
Runnable(준비 상태)
Running(실행 상태)
Terminated(실행 종료)
Blocked(지연 상태)
Runnable 인터페이스를 구현하는 것을 추천한다. Thread 클래스를 상속받으면 다른 클래스를 상속받지 못한다. 또한 Runnable을 구현하면 재사용성이 높고 코드의 일관성을 유지할 수 있으므로 더 객체지향적인 방법이다.
Runnable 인터페이스 구현 예제
실행되면 string 값을 출력하는 스레드를 만들었다.
public class ThreadExample {
public static void main(String[] args) {
Runnable r1 = new MyThread("*");
Runnable r2 = new MyThread("!");
Runnable r3 = new MyThread("&");
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
Thread t3 = new Thread(r3);
t1.start();
t2.start();
t3.start();
System.out.println("종료");
}
static class MyThread implements Runnable {
private String string;
public MyThread(String s) {
this.string = s;
}
@Override
public void run() {
System.out.println(string);
}
}
}
new로 스레드를 생성(New)하고, start() 메서드가 호출되면 스레드가 실행되기 위한 준비 단계(Runnable)가 된다. run() 메서드를 호출하여 스레드를 실행(Running)한다. run() 메서드가 종료되면 스레드는 실행을 종료(Terminated)한다.
실행 결과는 ! → * → 종료 → &
로 출력되기도 하고, 종료 → * → & → !
로 출력되기도 한다.
main 메서드에 의해 메인 스레드가 실행되며, new Thread()로 스레드 객체를 3개 생성하여 총 4개의 스레드가 동시에 실행되기 때문이다.
다음 시간에는 스레드를 사용하는 방법을 코드와 함께 더 살펴보겠다.
Ref