---
# System prepended metadata

title: ✏️ 자바의 버전별 스레드 관리 240311

---

# ✏️ 스레드
## zzawang


스레드의 생성자 종류를 보면 `Thread()`, `Thread(Runnable target)`, `Thread(Runnable target, String name)` 등 다양한데, 여기서 Runnable은 무엇일까? 

**Runnable interface**는 인스턴스가 스레드에 의해 실행되도록 모든 클래스에 의해 구현되어야 하는 interface이다. 생성자 안의 Runnable은 Runnable 인터페이스를 구현한 구현체이다. 따라서, `run()`메소드를 반드시 정의해야 한다. 우리가 RequestHandler 클래스의 `run()`메소드에서 정적인 html 파일을 응답하는 기능을 구현한 것도 이와 같은 이유이다.

* 자바 스레드 API 종류([참고 문서](https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html))
    - start()
    - sleep()
    - run()
    - join()
    - interrupt()
    - 등등 ...

<br>

* 스레드와 동기화
만약, 우리의 시스템이 하나의 스레드만 있는 싱글 스레드 시스템이라면 공유 데이터에 접근할 때 외부 상황을 고려하지 않아도 되지만, 다중 스레드라면 공유 데이터에 접근할 때 예상하지 못한 결과가 나올 수 있다. 이러한 문제를 해결해줄 수 있는 것이 **스레드 동기화**이다. 자바에서는 자바에서는 synchronized 키워드를 통해 메서드나 코드 블록에 작성하여 스레드 동기화를 할 수 있다. 
아래 코드는 synchronized 키워드를 사용하여 동기화를 하는 예시 코드이다.
    ```java
    class Money {
        private int myMoney = 10000;

        public int getMyMoney() {
            return myMoney;
        }

        // 메서드 전체를 임계영역으로 설정
        public synchronized boolean withdraw(int money) {
            if (myMoney >= money) {
                try {
                    Thread.sleep(1000);
                } catch (Exception e) {
                    System.out.println(e);
                }
                myMoney -= money;
                return true;
            }
            return false;
        }
    }
    ```



<br><br>

# ✏️ 자바의 버전별 스레드 관리 240311

## Sid
- 처음
    - Runnable과 Thread를 동기화된 클래스와 메서드를 이용해 사용
    - 단점:  
        - Thread
            - 별도의 클래스를 만들어야 함
            - 다중 상속이 불가능하므로 다른 클래스를 상속받을 수 없음
        - Runnable
            - 값을 반환받지 못한다
        - Thread, Runnable 둘 다
            -  모두 지나치게 저수준의 API에 의존
            -  쓰레드의 관리가 어렵다
- Java 5: 
    - Executor, ExecutorService 인터페이스
        - 스레드 실행과 태스크 제출을 분리하는 
    - Callable<T> 과 Future<T>
        - Runnable과 Thread의 변형
        - Callable은 값을 반환받을 수 있음
        - Future를 통해 유연하게 비동기 처리 과정을 변수에 저장, 처리 가능
- Java 7:
    - java.util.concurrent.RecursiveTask
        - 분할, 정복 알고리즘의 포크/조인 구현을 지원
- Java 8:
    - 스트림과 새로 추가된 람다 지원에 기반한 병렬 스트림(parallelStream())
        - ForkJoinPool 프레임워크를 이용해서 병렬 처리
    - CompletableFuture
        - 여러 비동기 작업을 조합 가능
        - 예외처리 가능
- Java 9:
    - Flow 인터페이스
        발생-구독 프로토콜을 지원하는 
    
    
    
## 데이
- 초기 자바에서는 Thread를 직접 상속하여 구현 후 사용하는 방식을 사용했다.
- java5부터 Executors를 통해 Thread pool을 생성할 수 있게 되었고, submit()으로 Runnable을 pool에 전달하는 식으로 좀 더 추상화 수준이 높아진 방식을 사용하게 되었다.
    - 실행되어야 하는 태스크는 ExecutorService에 submit 되고, 큐에 들어간다. 작업 가능한 스레드가 큐에서 태스크를 가져가서 실행한다.
    - 이제 우리는 스레드를 직접 생성하지 않고 사용한다. pool의 생성 및 관리는 ExecutorService가 담당한다.
- java7부터는 ExecutorService 기반으로 만들어진 Fork/Join 프레임워크가 도입됐다. Fork/join은 재귀적으로 더 작게 쪼개서 처리할 수 있는 태스크들을 효과적으로 처리할 수 있다.
    - ExecutorService와 다른 특징은 작업 빼가기(work-stealing)라는 것이다.
        - Thread pool에 존재하는 A라는 스레드가 현재 과부하 상태인 경우, 같은 Pool에 있는 B 스레드가 A 스레드 내부에 있는 스레드를 가져와서 처리하는 것을 의미한다.
- java8에서 CompletableFuture이 등장했다. Future에서 아쉬웠던 부분들이 개선되었는데, 함수형 인터페이스의 도입과 함께 더욱 자연스럽고 이해가 쉬운 코드로 표현할 수 있게 되었으며 연산 결과를 모아서 처리하고 에러를 핸들링 할 수 있게 되었다.
- Project Loom?
    - 가상 스레드를 사용하는 방식
    - 현재 자바의 스레드는 os 스레드와 1대1로 매칭되어 있는데, 여기서의 가상 스레드는 그것을 벗어나는 가상 스레드
    - https://cr.openjdk.org/~rpressler/loom/Loom-Proposal.html
    
[참고자료](https://homoefficio.github.io/2020/12/11/Java-Concurrency-Evolution/)
[참고자료(원문)](https://dzone.com/articles/java-concurrency-evolution)