- [Java 정리] Thread 12022년 08월 13일
- starryeye
- 작성자
- 2022.08.13.:19
반응형이미 알던 지식이지만, 기본으로 돌아가서.. Java의 관점에서 한번 정리해보자.
프로세스와 쓰레드
Process
실행 중인 프로그램(어플리케이션)
OS 커널로 부터 실행에 필요한 자원(가상 메모리)를 할당 받아 프로세스가 된다.
프로그램을 수행하는데 필요한 데이터와 메모리 등의 자원 그리고 쓰레드로 구성되어 있다.
하나의 프로세스 내에 쓰레드 개수는 제한 되어 있지 않지만,
쓰레드에 개별적인 메모리 공간(호출 스택)을 할당해주므로 프로세스의 메모리 한계에 따라 정해진다.
Thread
프로세스의 자원을 이용해서 실제로 작업을 수행하는 것이 쓰레드이다.
모든 프로세스는 최소한 하나 이상의 쓰레드가 존재한다.
둘 이상의 쓰레드를 가진 프로세스를 멀티 쓰레드 프로세스라 한다.
<참고>
스케쥴러는 프로세스 또는 쓰레드 실행 순서와 실행 시간을 결정한다.
OS는 프로세스의 스케줄러를 가진다.
JVM은 쓰레드의 스케줄러를 가진다.
하나의 자바프로그램은 하나의 프로세스이며 여러개의 쓰레드를 가질 수 있다.
멀티태스킹과 멀티쓰레딩
Multi-tasking
OS가 여러 개의 프로세스를 동시에 실행시키는 것.
(대부분의 OS는 이를 지원한다.)
Multi-threading
하나의 프로세스 내에서 여러 쓰레드가 동시에 작업을 수행하는 것이다.
CPU의 코어가 한 번에 하나의 작업만 수행 할 수 있으므로,
실제로 동시에 처리되는 작업의 개수는 코어의 개수와 일치한다.
(Spring Webflux가 코어당 하나 또는 두개의 쓰레드를 두고 작업한다.)
(반면 Spring MVC는 여러개의 쓰레드를 쓰레드 풀에 두고 사용한다.)
멀티 쓰레딩 장점
CPU 사용률 업!
자원을 효율적으로 사용
사용자 응답성 업!
작업 분리로 인한 코드 간결성 업!
멀티 쓰레딩 단점
동기화, 데드락 문제 해결해야 한다.
동기화는 락의 개념, 데드락은 자원 접근 우선순위를 두고 사용으로 간단하게 회피 가능하긴 하다.
하지만, 성능 상의 문제가 다시 생겨버림..
(구체적인 해결법 추후 포스팅..)
쓰레드 구현
//Thread클래스를 상속 받은 경우 class MyThread1 extends Thread { public void run() { //로직 구현 } } //Runnable 인터페이스를 구현한 경우 class MyThread2 implements Runnable { public void run() { //로직 구현 } } public static void main(String args[]) { //Thread클래스를 상속 받은 경우의 인스턴스 생성 MyThread1 t1 = new MyThread1(); //Runnable 인터페이스를 구현한 경우의 인스턴스 생성 Runnable r = new MyThread2(); Thread t2 = new Thread(r); //한줄로 Thread t2 = new Thread(MyThread2()); }Runnable 인터페이스

Runnable 인터페이스는 단순히 run 메서드만 정의되어있다..
따라서, Runnable 인터페이스를 구현하는 방법으로 쓰레드 동작 로직(run)을 구현할 때,
run 메서드 내부에서 Thread 클래스의 메서드를 사용하고 싶을 땐...
static Thread currentThread() 위의 static 메서드인 currentThread 메서드를 사용하여 현재 쓰레드의 참조를 얻어와야지
Thread 클래스의 메서드를 사용할 수 있다.
class MyThread implements Runnable { public void run() { //currentThread()로 현재 쓰레드의 참조를 얻었기 때문에 //getName() 메서드를 사용할 수 있다. System.out.println(Thread.currentThread().getName()); } }쓰레드의 실행, run() 메서드와 start() 메서드
쓰레드를 실행시키기 위해서는 start() 메서드를 호출 해야한다.
run() 메서드 호출은 단순히 선언된 run() 메서드를 호출하는 것.. 그 이상 그 이하도 아니다.
start()
새로운 쓰레드가 작업을 실행하는데 필요한 새로운 호출 스택을 생성한 후, run() 메서드를 호출한다.

위 그림에서 볼 수 있듯이, start() 메서드를 호출 하면 새로운 호출 스택이 생성되고
해당 호출 스택에서 run()메서드가 실행 되는 것을 볼 수 있다.
따라서, 앞으로...
main 쓰레드와 새로 생성된 쓰레드가 별도의 호출 스택을 가지고
스케줄러(JVM)이 정한 실행 순서와 실행 시간에 의해 번갈아 가며 실행 될 것이다.
프로세스의 종료 시점?
main 쓰레드의 호출 스택만 존재 했을 때는 main 쓰레드의 호출 스택이 모두 비워지면 프로세스가 종료 되었다.
하지만..
멀티 쓰레드 환경에서는
하나의 쓰레드의 호출 스택만 남아 있어도 프로세스는 종료되지 않는다.
(여기서 쓰레드는 사용자 쓰레드를 말한다. 데몬 쓰레드 X)
싱글 쓰레드와 멀티 쓰레드
CPU 코어는 한번에 하나의 쓰레드를 돌릴 수 있다.
CPU가 싱글 코어일 때를 상상해보자..
싱글 쓰레드로 두개의 작업을 돌릴 때..
-> 첫번째 작업이 끝나면 두번째 작업을 시작한다.
두개의 쓰레드로 각각 한개의 작업, 총 두개의 작업을 돌릴 때..
-> 두개의 쓰레드이지만 코어가 하나이므로 concurrency 하게 두개의 작업이 동시에 진행 되는 것 처럼 보이게 한다.
-> 두개의 작업은 절대로 겹치지 않는다.
-> 싱글 쓰레드 일 때 보다 시간이 더 오래걸린다. 왜냐하면 context switching 비용이 들기 때문이다.
CPU가 멀티 코어(2개 이상)를 가질 때를 상상해보자..
두개의 쓰레드로 각각 한개의 작업, 총 두개의 작업을 돌릴 때..
-> 싱글 코어일 때 보다 훨씬 빠른 작업 처리를 볼 수 있다.
-> 멀티 코어이므로 두개의 작업은 겹친다. (parallelism)
그러나.. 예를 들어...
두개의 작업이 동일한 자원에 접근해야 할 경우 race condition(경쟁 상태)이 되므로
완벽한 parallelism 을 달성 할 수 없다.
하지만..
두개의 작업이 서로 다른 자원에 접근한다면 굉장히 효율적으로 프로그래밍 된 케이스이다.
반응형'Java' 카테고리의 다른 글
[Java 정리] Thread 3 (0) 2022.08.19 [Java 정리] Thread 2 (0) 2022.08.13 [Java 정리] String, final, Immutable (0) 2022.08.05 [Java 정리] Garbage Collector 1 (0) 2022.07.30 [Java 정리] 내부 클래스 (0) 2022.07.28 다음글이전글이전 글이 없습니다.댓글