성장과정(dev)/Spring + Java + JPA

Java thread 와 프로세스에 대한 개념정리

lowellSunny 2025. 4. 5. 12:16

📘  Java 스레드의 주요 장점

  1. 멀티태스킹 지원
    • 여러 작업을 동시에 실행할 수 있어 사용자 경험이 부드러워짐.
    • 예: UI 응답 처리 + 백그라운드 데이터 처리
  2. CPU 자원 효율적 사용
    • 멀티코어 CPU 환경에서 여러 스레드가 병렬로 실행되어 성능 향상 가능.
  3. 응답성 향상
    • 무거운 작업(예: 파일 I/O, 네트워크 작업 등)을 별도 스레드로 처리하면 메인 스레드(UI 등)의 응답성 유지 가능.
  4. 공유 메모리 사용
    • 같은 프로세스 내에서 스레드는 메모리를 공유하기 때문에, 프로세스 간 통신(IPC)보다 빠르고 간단함.
  5. 비용이 적음
    • 새로운 프로세스를 생성하는 것보다 스레드 생성이 비용(시간과 자원) 면에서 훨씬 적음.
  6. 비동기 프로그래밍 용이
    • 특정 작업을 백그라운드에서 처리하고, 완료 시 콜백 처리 등의 구조를 만들기 쉬움.

🎯 예를들어 UI 렌더링과 로직 처리를 분리할 수 있음.

 

📘  멀티태스킹 지원, 뭐가 좋은데? 어차피 자원은 한정적이잖아

어차피 CPU 코어 수는 정해져 있고, 스레드를 수십 개 띄운다고 해서 물리적으로 동시에 전부 돌아가는 건 아니다. 그럼에도 불구하고 장점은 "자원을 최대한 활용하고, 사용자 경험을 개선"할 수 있기 때문

 

1. CPU가 노는 시간을 줄여준다 (I/O 대기 시간 활용)

  • 예: A 작업이 네트워크 요청 중이라 기다리는 동안 CPU는 놀고 있음.
  • 이때 B 스레드가 다른 작업을 하게 하면, 그 대기 시간을 다른 작업으로 메꿀 수 있음.
  • "진짜 동시 실행"은 아니더라도 효율은 올라감.

2. 사용자 경험(UX) 개선

  • 예: 메인 스레드가 화면 UI 처리 중인데, 백그라운드에서 파일 다운로드 같이 무거운 작업이 같이 돌아감.
  • 단일 스레드였다면? UI 멈춤, 앱 멈춤 느낌, 최악엔 "응답 없음".
  • 멀티스레드는 사용자는 계속 앱을 조작하고, 백그라운드에서 다른 일 처리 가능.

3. 논리적 동시성으로 효율적인 설계 가능

  • 하나의 스레드에 모든 걸 몰아 넣으면 설계 복잡도 폭발.
  • 역할 분리(예: 요청 처리 스레드, 로깅 스레드, 작업 처리 스레드)를 통해 유지보수성 향상.

4. 멀티코어 환경에서 실제 병렬 처리 가능

  • 코어가 4개 이상인 CPU에선 스레드들이 물리적으로 진짜 동시에 돌아감.
  • CPU 성능을 100% 활용 가능 ➜ 고성능 처리에 유리.

 

📘  Java 에서 스레드를 명시적으로 구현해주지 않으면 프로그램은 기본적으로 "단일 스레드(single-thread)" 환경에서 실행돼요.

기본적으로 main 함수는 단일스레드 이지만

우리가 직접 구현하지 않아도 Java 내부에서 스레드가 만들어져 돌아가는 경우 -> 자동스레드

  • 웹서버 (예: Tomcat) -클라이언트 요청마다 스레드를 만들어 처리
  • 스레드 풀 사용 - ExecutorService로 관리되는 스레드
  • 비동기 처리 -CompletableFuture.runAsync() 같은 경우도 내부적으로 스레드 사용
  • GUI 프로그램 (예: JavaFX, Swing) -이벤트 디스패치 스레드(EDT)가 따로 작동

 

📘 CompletableFuture API 설명 정리 (요약)

  주로 언제 사용하나요?

CompletableFuture는 비동기 프로그래밍을 깔끔하고 유연하게 하고 싶을 때 주로 사용돼요. 특히 콜백 지옥 피하고, 비동기 작업 간 연결(연쇄), 에러 처리, 병렬 실행 등을 다룰 때 진가를 발휘합니다.

 

✅ 기본 개요

  • Future처럼 값을 설정해서 완료할 수 있으며,
  • CompletionStage처럼 완료 시 실행될 함수나 작업을 지정할 수 있음.

✅ 완료 메서드 관련

  • complete, completeExceptionally, cancel 같은 완료 관련 메서드는
    여러 스레드가 동시에 호출하더라도 단 하나만 성공함.

✅ CompletionStage 구현 정책

  1. 비동기 아닌(non-async) 메서드에서 등록된 작업은:
    • 현재 CompletableFuture를 완료시키는 스레드,
    • 혹은 다른 완료 메서드 호출자 스레드가 실행함.
  2. 비동기(async) 메서드에서 Executor를 명시하지 않으면:
    • ForkJoinPool.commonPool() 사용됨.
    • 만약 해당 풀에서 병렬성 레벨이 2 이상 안 되면 → 새 스레드 생성.
    • 모든 비동기 작업은 AsynchronousCompletionTask 마커 인터페이스의 인스턴스임.
  3. 모든 CompletionStage 메서드는 독립적으로 구현됨:
    • 즉, 서브클래스에서 어떤 메서드를 오버라이드해도 다른 메서드의 동작에 영향 없음.

✅ Future 인터페이스 관련 정책

  1. FutureTask와 달리, 이 클래스는 직접 계산을 제어하지 않음.
    • 취소는 예외적인 완료로 간주됨.
    • cancel() 메서드는 내부적으로 completeExceptionally(new CancellationException()) 호출과 동일.
    • isCompletedExceptionally() 메서드로 예외적으로 완료되었는지 확인 가능.
  2. CompletionException으로 예외가 완료된 경우:
    • get()과 get(long, TimeUnit)은 내부 예외를 담은 ExecutionException을 던짐.
    • 대신, join()과 getNow()는 CompletionException 자체를 직접 던짐 (사용자 편의성을 위해 제공됨).

 

 

📘 Javascript 의 멀티스레드

Javascript 는 싱글스레드언어이지만 Java thred 를 사용하려면 Web worker 나 Worker Thread (Node.js 10.5.0 이상) 를 사용해서 멀티스레드를 구현할 수 있다. 

 

 

📘 자바기준에서 프로세스와 스레드 차이는? 

✔ 프로세스 (Process)

  • Java에서 ProcessBuilder나 Runtime.getRuntime().exec()으로 외부 프로그램을 실행하면 새로운 프로세스가 만들어짐.
  • 예: Java에서 Python 스크립트를 실행한다면, 그건 별개의 프로세스.

✔ 스레드 (Thread)

  • Java에서는 Thread 클래스를 이용해서 같은 프로세스 안에서 동시 실행 흐름을 만들 수 있음.

 

🎯 메모리 공유 차이

  • 스레드끼리는 힙 메모리 공유 ➜ 전역 변수, 객체 공유 가능
  • 프로세스끼리는 메모리 분리 ➜ 데이터를 주고받으려면 파일, 소켓, 파이프 등 IPC 필요

 

📘 Java에서 프로세스를 사용하는 경우

  • MSA : 로그인서비스, 결제서비스, 검색 서비스 각각 다른 프로세스로 구동하는 경우
    • 참고로, 이전 회사에서는 프로세스별로 쪼개는 것이 아닌, 별도의 서버로 올려서 사용했었다. MSA 는 일반적으로 컨테이너가 분리된다. 구조적인 관점으로만 보기 !!
  • Java 웹서버는 backend (비지니스로직), Python 은 AI 처리를 하는 경우

 

📘 Java에서 스레드를 사용하는 경우

  • 같은 서비스/기능 내에서 동시에 여러 작업을 처리해야 할 때
  • 사용자 요청 처리, 백그라운드 작업, 비동기 이벤트 등

💡 예시

  • Java 웹 서버(Tomcat, Jetty 등)는 클라이언트 요청마다 새 스레드 생성
  • 스프링에서 @Async, CompletableFuture 같은 비동기 처리
  • 스레드 풀을 통한 워커 스레드 관리 (ExecutorService)