동기 Sync
- 요청을 보내면 결과가 올 때까지 기다리는 방식입니다.
- 요청 → 결과 올 때까지 기다림 → 다음 작업 진행
- 순차적, 차례대로 실행됨.
코드를 보면서 이해하자
public class SyncExample {
public static void main(String[] args) {
System.out.println("작업 시작");
task("A");
task("B");
task("C");
System.out.println("작업 끝");
}
public static void task(String name) {
try {
Thread.sleep(1000); // 1초 대기
System.out.println("작업 " + name + " 완료");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
결과로 task함수가 순차적으로 실행되어 A, B, C가 순차적으로 완료되고 작업 끝이 출력된다.
작업 시작
(1초 후) 작업 A 완료
(1초 후) 작업 B 완료
(1초 후) 작업 C 완료
작업 끝
동기와 비동기의 차이를 보고 가자.
| 항목 | 동기(Sync) | 비동기(Async) |
| 장점 | 흐름이 직관적이다 (코드 읽기 쉽다) | 자원을 효율적으로 사용 가능 (대기 시간 활용) |
| 단점 | 대기 시간이 생기면 전체 흐름이 멈춘다 | 코드 복잡도가 올라간다 (콜백, 에러 처리 등) |
| 속도 | 느릴 수 있다 (대기시간 포함) | 빠르게 보인다 (다른 작업 먼저 처리) |
| 작업순서 | 순차적으로 처리됨 | 요청 후 바로 다음작업 가능 |
| 응답 대기 방식 | 결과 올 때 까지 다음작업 안함 | 결과 안기다리고 바로 다음작업 진행 |
비동기 Async
- 요청을 보내고 기다리지 않고 바로 다른 작업을 진행하는 방식입니다.
- 요청 → 기다리지 않음. 다른 작업함 → 결과가 오면 알림(콜백, Promise, async/await)
코드를 보며 이해해 보자
public class AsyncExample {
public static void main(String[] args) {
System.out.println("작업 시작");
new Thread(() -> task("A")).start();
new Thread(() -> task("B")).start();
new Thread(() -> task("C")).start();
System.out.println("작업 끝");
}
public static void task(String name) {
try {
Thread.sleep(1000); // 1초 대기
System.out.println("작업 " + name + " 완료");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
결과로 거의 동시에 A, B, C가 완료되어 print 되는 걸 볼 수 있음.
작업 시작
작업 끝
(1초 후) 작업 A 완료
(1초 후) 작업 B 완료
(1초 후) 작업 C 완료
자바 코드를 보면 비동기 방식을 구현하기 위해 멀티쓰레드를 사용했다.
하지만 멀티쓰레드를 사용해야지만 비동기 방식인 것은 아니다.
비동기란 "어떤 작업이 끝날 때까지 기다리지 않고 다음 일을 진행하는 것"
자바스크립트는 단일쓰레드지만 비동기 처리가 가능하다.
console.log("A");
setTimeout(() => console.log("B"), 1000);
console.log("C");
// 결과는 아래와 같다.
// A → C → (1초 후) B
그냥 console.log를 찍고 결과를 1초 대기시킨 듯 하지만,
이 코드가 비동기라고 하는 이유는 setTimeout 함수의 특성 때문임.
setTimeout()은 타이머를 설정하는 비동기 함수로, 주어진 시간이 지난 후에 특정 작업을 실행하도록 예약한다.
즉, 대기하는 동안 다른 작업을 차례대로 진행할 수 있게 해주는 특성을 가지기 때문.
A를 출력하고 타이머가 끝나면 실행될 B를 예약하고 C를 출력한다.
setTimeout() 자체는 동기로 실행되지만 setTimeout이 예약하는 작업(여기서는 console.log("B"))이 비동기적이어서 타이머 대기 중 다른 코드들이 실행되는 것임.
| 구분 | 설명 |
| 비동기(Asynchronous) | 어떤 작업의 완료를 기다리지 않고 다음 작업을 이어서 수행하는 방식. |
| 스레드(Thread) | 작업을 병렬로 수행하기 위한 실행 단위. |
| 동기 = 단일 스레드?? | → ㄴㄴ 멀티 스레드에서도 동기 가능 |
| 비동기 = 멀티 스레드?? | → ㄴㄴ 단일 스레드에서도 비동기 가능 |
| 스레드 수가 개념 차이를 만든다?? | → ㄴㄴ 개념은 "기다리는가?"가 핵심 |
Synchronous? 자바에서 Synchronized는 뭘까?
멀티쓰레드 환경에서 공유 자원에 대한 동시 접근 문제를 해결하기 위한 키워드.
- 여러 쓰레드가 동시에 같은 데이터에 접근하면, 데이터 정합성 문제가 발생할 수 있다.
- synchronized는 한 번에 하나의 쓰레드만 특정 코드 블록이나 메서드에 접근하도록 제한하여, 데이터의 안정성과 신뢰성을 확보 가능.
- 하지만 무분별하게 사용하면 병목과 성능 저하를 유발할 수 있으니, 잘 알아보고 꼭 필요한 최소 범위에서 사용하자.
| 구분 | 의미 | 관련 |
| synchronous (동기) | 작업을 순차적으로 처리하는 실행 방식. | 실행 흐름 제어 방식 |
| synchronized (동기화) | 멀티쓰레드에서 자원 충돌을 막기 위한 키워드. | 자원 보호 / 동시성 문제 해결 |
synchronous는 자바의 키워드가 아니고, 어떤 작업 방식을 의미. 예: 함수 호출이 끝날 때까지 기다리는 방식.
synchronized는 자바의 예약어(keyword)로, 멀티쓰레드 환경에서 데이터 충돌을 막기 위해 lock을 걸어주는 역할.
동기/비동기 와 blocking/non-blocking 은 독립적인 속성이다.
동기/비동기는 작업의 흐름을 설명하는 개념이며,
블로킹과 논블로킹은 리소스 점유 여부에 관한 개념이다.
blocking과 nonBlocking
blocking - 작업이 끝날 때까지 호출한 쪽이 멈춰서 기다림 (실행 중단)
nonBlocking - 작업을 요청만 하고 다음 작업으로 넘어감, 결과는 나중에 받음
| 구분 | 블로킹(Blocking) | 논블로킹(Non-Blocking) |
| 리소스 점유 여부 | 리소스를 점유하고 기다림 | 기다리지 않고 바로 반환 |
| 실행 흐름 | 멈춰 있음 | 멈추지 않고 다른 일 가능 |
| 예: | 전화 통화 중 통화 끝날 때까지 기다림 | 문자 메시지 보내고 답 오기 전에도 다른 일 가능 |
동기 + blocking
const data = fs.readFileSync('file.txt'); // 파일 읽을 때까지 멈춤
console.log(data);
- 동기(Synchronous): fs.readFileSync()는 결과를 즉시 반환하지 않고, 작업이 끝날 때까지 기다린 다음에야 다음 줄(console.log(data))로 넘어감.
- Blocking: 해당 작업(파일 읽기) 동안 현재 실행 흐름이 멈춤. CPU도 대기 중이며, 다른 작업이 병렬로 못 돌아감.
이점으로
- 코드 흐름이 직관적: 순차적이므로 디버깅이나 예측이 쉬움.
- 작은 파일 / 간단한 작업에는 오히려 효율적.
비동기 + blocking
function asyncButBlocking(callback) {
// 내부에서 blocking 작업 (ex. CPU-intensive 또는 동기 I/O)
const fs = require('fs');
const data = fs.readFileSync('file.txt'); // blocking
callback(null, data); // 결과는 콜백으로 주긴 함
}
asyncButBlocking((err, data) => {
console.log(data);
});
console.log('다음 작업'); // 블로킹 때문에 늦게 출력됨
비동기처럼 생겼지만, 내부에서는 blocking 작업을 하고 있음 (의미 없음)
동기 + nonBlocking
function fakeSyncNonBlockingRead() {
// 실제로는 데이터를 읽지 않고 즉시 리턴 (non-blocking)
return '캐시된 데이터';
}
const data = fakeSyncNonBlockingRead(); // 동기 호출
console.log(data);
console.log('다음 작업');
함수는 동기적으로 흐르는데, 내부적으로는 non-blocking 자원(I/O 등)을 써서 빨리 리턴함.
비동기 + nonBlocking
fs.readFile('file.txt', (err, data) => {
console.log(data);
});
console.log('다음 작업'); // 먼저 출력됨
- 비동기(Asynchronous): fs.readFile()은 파일 읽기를 요청만 하고 즉시 반환함. 콜백은 나중에 실행됨.
- Non-Blocking: fs.readFile() 호출 자체는 기다리지 않고 **다음 줄(console.log)**로 즉시 넘어감. → 실행 흐름을 막지 않음.
이점으로
- 다른 작업을 병렬로 처리 가능 (예: 서버 요청, UI 반응)
- 대규모 처리에서 훨씬 성능 우위 (비용 높은 작업을 "대기 없이" 분산 처리)
단, 콜백지옥이 발생할 수 있으니 조심하자.
정리하자면,
| 조합 | 설명 |
| 동기 + 블로킹 | 일반적인 순차적 실행, 응답 올 때까지 아무것도 못함 |
| 동기 + 논블로킹 | 요청은 순차적이지만, 결과 기다리며 멈추지 않음 |
| 비동기 + 블로킹 | 요청은 비동기로 보내지만, 결과 기다리면서 멈춤 (잘 안 씀) |
| 비동기 + 논블로킹 | 가장 많이 쓰는 방식, 요청하고 다른 일도 하면서 결과 오면 처리 |
일반적으로 동기+블로킹, 비동기+논블로킹 조합을 사용한다.
'정리' 카테고리의 다른 글
| 싱글톤패턴 (0) | 2025.04.29 |
|---|---|
| 자바 동시성이슈 (0) | 2025.04.28 |
| RDBMS vs NoSQL (0) | 2025.04.26 |
| Collection정리하기 List, Set, Map (0) | 2025.04.25 |
| 스프링 (0) | 2025.04.22 |