Notice
Recent Posts
Recent Comments
Link
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
Tags
more
Archives
Today
Total
관리 메뉴

이지은님의 블로그

250310 - 동기와 비동기, 블로킹과 언블로킹, 데이터베이스 활용 개념 정리(Sync vs Async & Blocking vs Non-Blocking, Server/In-memory/Embedded Mode) 본문

TIL

250310 - 동기와 비동기, 블로킹과 언블로킹, 데이터베이스 활용 개념 정리(Sync vs Async & Blocking vs Non-Blocking, Server/In-memory/Embedded Mode)

queenriwon3 2025. 3. 11. 01:30

 오늘 배운 

세션과 JPA 심화공부를 하면서 몰랐던 부분을 따로 정리하고자 한다.

 

<<목차>>

1. 동기/비동기와 블로킹/논블로킹

    1) 동기(Synchronous) vs 비동기(Asynchronous)

    2) Blocking vs Non-Blocking

    3) Sync vs Async & Blocking vs Non-Blocking 차이

2. 동시성과 병렬성

    1) 동시성(Concurrency) vs 병렬성(Parallelism)

    2) 적용사례

3. DB의 사용방식(H2 기준)

    1) Server Mode

    2) In-memory Mode

    3) Embedded Mode

4. 데이터베이스 Driver

    1) 데이터베이스 Driver 역할 및 종류

    2) 데이터베이스 Driver 동작

 


 

 

1. 동기/비동기와 블로킹/논블로킹

1) 동기(Synchronous) vs 비동기(Asynchronous)

 

1️⃣ 동기(Synchronous, Sync)

  • 한 작업이 완료될 때까지 대기한 후 다음 작업을 수행하는 방식
  • 순차적으로 실행되므로 코드의 실행 흐름을 예측하기 쉽지만, 속도가 느릴 수 있음
  • 특정 작업이 오래 걸릴 경우 다른 작업이 블로킹(Blocking)됨

 

 

2️⃣ 비동기(Asynchronous, Async)

  • 한 작업을 실행하는 동안 다른 작업을 동시에 수행 가능
  • 시간이 오래 걸리는 작업(예: API 호출, 데이터베이스 조회, 파일 처리)을 비동기로 처리하면 성능이 향상됨
  • Java에서는 @Async, CompletableFuture, ExecutorService, Reactor(WebFlux) 등을 이용하여 비동기 처리 가능
@Service
public class AsyncService {

    @Async  // 별도 스레드에서 실행됨(비동기스레드)
    public CompletableFuture<String> fetchDataAsync() {
        try {
            Thread.sleep(3000);  // 3초 대기
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return CompletableFuture.completedFuture("비동기 처리 완료");  // 비동기 스레드가 실행된 후 완료 출력
    }
}


@RestController
@RequestMapping("/api")
public class AsyncController {
    
    ...

    @GetMapping("/async")
    public CompletableFuture<String> getAsyncData() {
        System.out.println("비동기 요청 시작"); //로거 그냥 안씀
        CompletableFuture<String> future = asyncService.fetchDataAsync();
        System.out.println("비동기 요청 종료");
        return future;
    }
}

// 비동기 요청 시작 
// 비동기 요청 종료
// 비동기 처리 완료

 

 

 

3️⃣ 동기와 비동기 방식의 비교

비교 항목 동기 비동기
작업 처리 방식 순차적으로 실행 동시에 여러 작업 가능
응답 대기 여부 요청이 끝날 때까지 대기 결과를 기다리지 않고 즉시 다음 코드 실행
성능 속도가 상대적으로 느림 대규모 트래픽에서 성능 향상
사용 방식 일반 메서드 호출 @Async, CompletableFuture, ExecutorService
적용 예제 CRUD, 데이터 조회 대량 데이터 처리, 비동기 API

 

 

 

 

2) Blocking vs Non-Blocking

1️⃣ Blocking (블로킹)

  • 작업을 수행할 때 결과가 나올 때까지 현재 스레드가 멈춰있는 방식
  • 요청을 보낸 스레드는 결과를 받을 때까지 아무 작업도 하지 못하고 기다림

사용방법) Java InputStream.read(), JDBC (전통적인 DB 연동)

public class BlockingIOExample {
    public static void main(String[] args) {
        try (BufferedReader reader = new BufferedReader(new FileReader("data.txt"))) {
            String line = reader.readLine();  // 파일 읽기 작업이 끝날 때까지 블로킹됨
            System.out.println("읽은 데이터: " + line);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

// (파일을 읽을 때까지 프로그램이 멈춰있음)
// 읽은 데이터: Hello World

 

 

 

2️⃣ Non-Blocking (논블로킹)

  • 작업을 요청한 후, 즉시 제어권을 반환하고 다른 작업을 수행할 수 있는 방식
  • 요청을 보낸 스레드는 응답을 기다리지 않고 다른 작업을 수행 가능

사용방법) Java NIO (Non-blocking I/O), WebFlux, Netty

import java.nio.file.*;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.CompletableFuture;

public class NonBlockingIOExample {
    public static void main(String[] args) {
        System.out.println("파일 읽기 시작");
      
        // 비동기  
        CompletableFuture.supplyAsync(() -> {
            try {
                return Files.readString(Path.of("data.txt"), StandardCharsets.UTF_8);
            } catch (Exception e) {
                e.printStackTrace();
                return "";
            }
        }).thenAccept(content -> System.out.println("읽은 데이터: " + content));
        // .thenAccept(): try-catch구문이후 실행됨

        System.out.println("다른 작업 수행 중...");
    }
}

// 파일 읽기 시작
// 다른 작업 수행 중...
// 읽은 데이터: Hello World
비교 항목 Blocking Non-Blocking
작업 처리 방식 요청을 보낸 응답이 때까지 대기 요청을 보낸 즉시 다음 작업 수행 가능, 유연한 스레드 진행
예제 InputStream.read(), JDBC Java NIO, CompletableFuture
스레드 효율 하나의 요청이 하나의 스레드를 점유 하나의 스레드가 여러 요청을 처리 가능
적용 예시 일반적인 파일 I/O, JDBC 연결 WebFlux, Netty 기반 서버
장점 코드가 직관적이고 이해하기 쉬움 성능 향상 (특히 대량 요청 처리 유리)
단점 응답 대기 시간이 길어지면 성능 저하 코드가 복잡해질 있음

 

 

 

3) Sync vs Async & Blocking vs Non-Blocking 차이

개념 Sync Async Blocking Non-Blocking
작업 방식 요청을 보낸 결과를 기다림 요청을 보낸 결과를 기다리지 않음 작업 완료까지 스레드가 멈춤 작업이 끝나지 않아도 바로 반환
스레드 활용 요청마다 스레드 점유 하나의 스레드가 여러 작업 처리 가능 하나의 작업이 끝날 때까지 다른 작업 수행 불가 하나의 스레드가 여러 작업을 수행 가능
대표적인 방식 일반적인 함수 호출,CRUD @Async, CompletableFuture Thread.sleep(), InputStream.read() Java NIO, WebFlux, Netty
예제 fetchData() 대기 fetchDataAsync() 다른 작업 수행 readFileBlocking() readFileNonBlocking()

 

Blocking vs Non-Blocking은 "작업이 완료될 때까지 기다리는가?"의 차이

  • Blocking → 스레드가 멈춰서 기다림
  • Non-Blocking → 스레드가 기다리지 않고 다른 작업 수행 가능

Sync vs Async는 "작업이 순차적으로 실행되는가?"의 차이

  • Sync → 이전 작업이 끝나야 다음 작업 시작
  • Async → 여러 작업을 동시에 진행 가능

 

 

 

2. 동시성과 병렬성

1) 동시성(Concurrency) vs 병렬성(Parallelism)

1️⃣ 동시성(Concurrency)

  • 하나의 CPU(코어)에서 여러 작업을 번갈아가며 실행하는 방식
  • 실제로 같은 순간에 여러 작업이 실행되는 것이 아니라 작업 간 전환(Context Switching)을 통해 빠르게 수행되는 것처럼 보임
  • 멀티스레드(Multi-threading), 비동기(Async) 프로그래밍과 관련됨
public class ConcurrencyExample {
    public static void main(String[] args) {
        Runnable task1 = () -> {
            for (int i = 0; i < 5; i++) {
                System.out.println("Task 1 실행 중...");
                try { Thread.sleep(100); } catch (InterruptedException ignored) {}
            }
        };

        Runnable task2 = () -> {
            for (int i = 0; i < 5; i++) {
                System.out.println("Task 2 실행 중...");
                try { Thread.sleep(100); } catch (InterruptedException ignored) {}
            }
        };

        new Thread(task1).start();
        new Thread(task2).start();
    }
}


번갈아가면서 실행됨

Task 1 실행 중...
Task 2 실행 중...
Task 1 실행 중...
Task 2 실행 중...
...

 

 

 

2️⃣ 병렬성(Parallelism)

  • 여러 개의 CPU(멀티코어)를 활용하여 여러 작업을 완전히 동시에 실행하는 방식
  • 멀티코어 시스템에서 각 작업이 독립적으로 실행되며 속도가 크게 향상됨
  • 멀티프로세싱(Multi-processing), 병렬 스트림(Parallel Streams), ForkJoinPool 관련됨
public class ParallelExample {
    public static void main(String[] args) {
        IntStream.range(1, 10).parallel().forEach(i -> 
            System.out.println(Thread.currentThread().getName() + " - Task " + i)
        );
    }
}


ForkJoinPool.commonPool-worker-1 - Task 2
ForkJoinPool.commonPool-worker-2 - Task 3
ForkJoinPool.commonPool-worker-3 - Task 1
ForkJoinPool.commonPool-worker-1 - Task 4
...

 

 

 

3️⃣ 동시성(Concurrency) vs 병렬성(Parallelism) 차이점

동시성(Concurrency) vs 병렬성(Parallelism) 차이

비교 항목 동시성(Concurrency) 병렬성(Parallelism)
개념 여러 작업을 번갈아 실행 (스레드 전환) 여러 작업을 완전히 동시에 실행
CPU 개수 단일 CPU에서도 가능 멀티코어 CPU 필요
작업 방식 여러 작업을 빠르게 스위칭하여 처리 여러 작업을 동시에 실행
적용 기술 멀티스레딩, 비동기 처리 멀티프로세싱, 병렬 연산
장점 하나의 CPU로도 다중 작업 가능 성능 최적화, 대량 데이터 병렬 처리
단점 스레드 전환 오버헤드 발생 멀티코어 환경에서만 효과적, 비쌈
예제 서버의 요청 처리, 비동기 이벤트 루프 머신러닝 연산, 대량 데이터 처리
정리 => 실제로는 번에 하나의 작업만 실행되지만, 빠른 전환(Context Switching)으로 여러 작업이 동시에 실행되는 것처럼 보이는 => 실제로 여러 개의 작업이 동시에 실행됨

 

 

 

2) 적용사례

1️⃣ 동시성이 필요한 경우

  • 웹 서버 요청 처리 (Spring MVC): HTTP 요청이 많을 때 멀티스레드를 사용하여 여러 요청을 동시 처리
  • 게임 캐릭터 행동

2️⃣ 병렬성이 필요한 경우

  • 머신러닝 모델 학습
  • 비디오 렌더링

 

 

3. DB 사용방식(H2 기준)

1) Server Mode

  • 직접 엔진을 설치하여 사용하는 방식(현업에서 주로 사용)
  • 애플리케이션과 상관 없는 외부에서 DB 엔진이 구동된다. -> 여러 애플리케이션에서 동일한 DB를 사용하기에 적합
  • 데이터가 애플리케이션 외부에 저장되므로 애플리케이션을 종료해도 데이터가 사라지지 않는다.

 

2) In-memory Mode

  • 엔진을 설치하지 않고 애플리케이션 내부의 엔진을 사용하는 방식.
  • 애플리케이션을 실행하면 DB 엔진이 함께 실행되고 애플리케이션을 종료하면 DB 엔진이 함께 종료된다. -> 휘발성: 데이터가 애플리케이션의 메모리에 저장되기 때문에 애플리케이션이 종료되면 모든 데이터가 사라짐(단위 테스트)
  • 데이터가 애플리케이션의 메모리에 저장되기 때문에 애플리케이션을 종료하면 데이터가 사라진다.
  • build.gradle 및 application.properties 설정을 통해 실행 가능하다.

 

(mem을 url에 작성)

# application.yml
spring:  
    datasource:    
        driver-class-name: org.h2.Driver
        url: jdbc:h2:mem:{DB 이름}
        username: sa
        password:

# application.properties
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:{DB 이름}
spring.datasource.username=sa
spring.datasource.password=

 

 

 

3) Embedded Mode

  • 엔진을 설치하지 않고 애플리케이션 내부의 엔진을 사용하는 방식.
  • 애플리케이션을 실행하면 DB 엔진이 함께 실행되고 애플리케이션을 종료하면 DB 엔진이 함께 종료된다. (In-memory mode 특징)
  • 데이터가 애플리케이션 외부에 저장되므로 애플리케이션을 종료해도 데이터가 사라지지 않는다. (Server mode 특징)

 

(url에 데이터가 저장될 경로 설정)

# application.yml
spring:
  datasource:
      driver-class-name: org.h2.Driver
      url: jdbc:h2:{DB가 저장될 경로}    
      username: sa    
      password:

# application.properties
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:{DB가 저장될 경로}
spring.datasource.username=sa
spring.datasource.password=

 

Mode H2 다운로드 여부 실행 주체 DB 저장 위치 사용 용도
Server Mode O 외부 로컬(파일 시스템) 배포 용도
In-Memory Mode X 스프링 메모리 테스트 용도
Embedded Mode X 스프링 로컬(파일 시스템) 개발 용도

 

 

 

 

4. 데이터베이스 Driver

1) 데이터베이스 Driver 역할 및 종류

  • 드라이버의 역할: 데이터베이스 드라이버는 애플리케이션과 데이터베이스 간의 통신을 중개하는 역할을 합니다. 마치 우체부가 편지를 전달하는 것처럼, 드라이버는 애플리케이션의 요청을 데이터베이스가 이해할 수 있는 언어로 변환
  • 드라이버의 종류: 다양한 데이터베이스 시스템마다 호환되는 드라이버가 있습니다. 예를 들어, Oracle, MySQL, PostgreSQL 데이터베이스 제품에 맞는 특정 드라이버가 필요

 

 

2) 데이터베이스 Driver 동작

1️⃣ 연결 초기화

  • 요청 수신: 애플리케이션은 데이터베이스 작업을 시작하기 위해 드라이버에 연결을 요청
  • 연결 설정: 드라이버는 데이터베이스 서버에 로그인하고 필요한 설정을 수행하여 연결을 완료합니다. 이 과정은 네트워크 정보, 인증 자격 증명 등을 사용하여 이루어짐.

2️⃣ SQL 전송 및 실행

  • SQL 명령 변환: 애플리케이션에서 발송된 SQL 명령을 받은 드라이버는 해당 명령을 데이터베이스가 이해할 수 있는 형태로 변환.
  • 명령 처리: 변환된 명령은 데이터베이스 서버로 전송되어 실행. 데이터베이스는 쿼리를 처리하고, 요구된 데이터를 검색하거나 데이터에 변화.

3️⃣ 결과 처리

  • 결과 수신: 데이터베이스에서 작업의 결과를 보내면, 드라이버는 이 결과를 받아 애플리케이션에서 해석할 수 있는 형태로 변환.
  • 결과 전달: 최종적으로, 드라이버는 이 결과를 애플리케이션에 전달. 애플리케이션은 이 정보를 사용자에게 표시하거나 다음 작업을 진행.

4️⃣ 연결 종료

  • 연결 해제: 작업이 완료되면, 드라이버는 데이터베이스 서버와의 연결을 종료. 자원을 정리하고 다음 세션을 위해 시스템을 초기화합니다.