📝느낀 점
이번 학습을 통해 동기와 비동기, 블로킹과 논블로킹의 개념을 명확히 이해하는 것이 얼마나 중요한지 깨달았습니다. 이러한 개념들은 성능 최적화와 사용자에게 직접적으로 영향을 미치기 때문이라고 생각합니다. Java에서 이러한 개념들을 직접 코드로 구현하고 실습해보면서, 어떤 상황에서 어떤 방식을 선택해야 할지에 대한 명확한 기준을 세울 필요성을 느끼게 되었습니다. 따라서 이를 공부하며 블로그에 기록을 남기기로 했습니다. 특히, 비동기 프로그래밍은 처음에는 복잡하게 느껴졌지만, 제대로 활용하면 매우 중요한 도구가 될 수 있다는 것을 깨달았습니다. 비동기 프로그래밍을 통해 작업을 효율적으로 처리하고, 응답성을 높여 사용자 경험을 개선할 수 있다는 것을 알게 되었습니다. 이번 기회를 통해 각 개념을 더욱 깊이 이해하고, 실제 코드에 적용해보는 과정을 통해 많은 것을 배울 수 있었습니다. 앞으로도 다양한 상황에서 이 개념들을 적용해보며, 보다 효율적인 코드를 작성하는 데 도움이 될 것이라고 생각합니다.
개념 이해하기
프로그래밍에서는 코드가 실행되는 방식에 따라 코드로 나눌 수 있습니다.
- 블로킹(blocking)
- 어떤 작업이 완료될 때까지 현재 스레드가 기다리는 방식입니다.
- 다른 작업을 할 수 없습니다.
- 논블로킹(non-blocking)
- 어떤 작업이 완료될 때까지 기다리지 않고 바로 다음 작업을 수행할 수 있는 방식입니다.
- 동기(synchronous)
- 작업이 순서대로 실행됩니다.
- 이전 작업이 완료될 때까지 다음 작업이 시작되지 않습니다.
- 비동기(asynchronous)
- 작업이 비동기적으로 실행되며, 다른 작업이 완료될 때까지 기다리지 않고 즉시 다음 작업을 수행할 수 있습니다.
이러한 개념을 이해하면 응답성이 높은 효율적인 프로그램을 작성하는 데 큰 도움이 된다고 생각합니다.
이번 글에서는 각 개념을 설명하고, 간단한 예제 코드를 통해 어떻게 구현되는지 기록을 남기도록 하겠습니다.
블로킹 (blocking)
[요청] → [대기] → [응답]
A 함수가 B 함수를 호출 할 때, B 함수가 자신의 작업이 종료되기 전까지 A 함수에게 제어권을 돌려주지 않는 것입니다.
- e.g.) 상사에게 서류를 제출하였는데, 상사가 "다 볼때까지 기다리세요" 라고 말한다.
그렇다면, 나는 다른일을 하지 못하고 기다리고 있어야 하는 것이다
블로킹 코드는 특정 작업이 완료될 때까지 코드의 실행이 멈추는 것을 말합니다.
블로킹 코드의 가장 일반적인 예로는 Thread.sleep() 메서드를 사용하여 현재 스레드를
지정된 시간 동안 정지시키는 것입니다.
다음은 블로킹 코드의 예시입니다:
public class BlockingCodeExample {
public static void main(String[] args) {
System.out.println("시작");
// 블로킹 코드: 3초 동안 현재 스레드를 정지시킴
System.out.println("기다리는 중...");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("블로킹 코드 후의 실행");
}
}
``` 출력값
시작
기다리는 중...
블로킹 코드 후의 실행
```
설명
위의 코드에서 Thread.sleep(3000)은 현재 스레드를 3초 동안 정지시키며, 그동안 다음 코드는 실행되지 않습니다.
System.out.println("기다리는 중...");
메시지가 출력된 후 3초 동안 기다렸다가 System.out.println("블로킹 코드 후의 실행"); 메시지가 출력됩니다.
이처럼 블로킹 코드는 특정 작업이 완료될 때까지 다른 작업을 할 수 없게 만듭니다.
논블로킹 (non-blocking)
[요청] → [다른 작업] → [응답] → [콜백]
A함수가 B함수를 호출 할때, B함수가 제어권을 바로 A함수에게 넘겨주면서,
A함수가 다른 일을 할 수 있도록 하는 것입니다.
논블로킹 코드는 특정 작업이 완료될 때까지 기다리지 않고, 다른 작업을 수행할 수 있는 코드를 말합니다.
Java에서 저는 CompletableFuture를 사용하여 비동기 작업을 구현할 수 있습니다.
다음은 논블로킹 코드의 예시입니다:
public class NonBlockingCodeExample {
public static void main(String[] args) {
System.out.println("시작");
// 비동기 작업을 수행하는 CompletableFuture
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
// 비동기적으로 수행될 작업
System.out.println("비동기 작업이 실행됩니다.");
});
// 다른 작업을 수행할 수 있음
System.out.println("다른 작업을 수행합니다.");
// 비동기 작업이 완료될 때 실행할 콜백 등록
future.thenRun(() -> System.out.println("비동기 작업이 완료되었습니다."));
System.out.println("프로그램 종료");
}
}
``` 출력값
시작
다른 작업을 수행합니다.
비동기 작업이 실행됩니다.
비동기 작업이 완료되었습니다.
프로그램 종료
```
설명
위의 코드에서 CompletableFuture.runAsync()를 사용하여 비동기 작업을 시작합니다.
thenRun() 메서드는 비동기 작업이 완료될 때 실행할 콜백을 등록합니다.
이로 인해 "다른 작업을 수행합니다."와 "프로그램 종료" 메시지가 즉시 출력되고,
비동기 작업이 완료되면 "비동기 작업이 완료되었습니다." 메시지가 출력됩니다.
이렇게 하면 비동기 작업이 완료될 때까지 메인 스레드가 기다리지 않고 다른 작업을 계속 수행할 수 있습니다.
동기 (synchronous)
[작업 1] → [작업 2] → [작업 3]
A() 함수가 B() 함수를 호출 할 때, B() 함수의 결과를 A() 함수가 처리하는 것입니다.
Synchronous은 Return을 기다리는 동안 머물 수도 아닐 수도 있습니다.
Blocking / sync 조합은 자바에서 사용됩니다.
동기화된 코드는 작업이 순서대로 차례차례 실행되는 것을 말합니다.
메서드를 호출하거나 블록 내에서 코드를 실행할 때,
다른 스레드가 해당 작업이 완료될 때까지 기다리게 할 수 있습니다.
다음은 동기 코드의 예시입니다:
public class SynchronousCodeExample {
public static void main(String[] args) {
System.out.println("시작");
// 동기화된 메서드를 호출하여 동기적으로 작업을 수행
synchronousMethod();
System.out.println("동기화된 코드 후의 실행");
}
private static void synchronousMethod() {
// 동기화된 메서드 내에서 작업 수행
System.out.println("동기화된 메서드 내에서 작업을 수행합니다.");
}
}
``` 출력값
시작
동기화된 메서드 내에서 작업을 수행합니다.
동기화된 코드 후의 실행
```
설명
위의 코드에서 synchronousMethod()가 호출되면,
해당 메서드 내의 작업이 완료될 때까지 다음 코드는 실행되지 않습니다.
따라서 "동기화된 메서드 내에서 작업을 수행합니다." 메시지가 출력된 후에
"동기화된 코드 후의 실행" 메시지가 출력됩니다.
동기 코드는 작업이 순차적으로 실행되므로 이해하기 쉽고 디버깅하기 용이하다고 생각합니다.
비동기 (asynchronous)
[작업 1] → [작업 2 완료] → [작업 3]
A() 함수가 B() 함수를 호출 할 때, B() 함수의 결과를 B() 함수가 처리하는 것입니다.
- async는 결과를 바로 처리하는 것이 아닙니다.
즉, 작업이 끝난 결과를 바로 처리하지 않고 자신의 일이 끝나게 되면 그때서야 처리를 하는 느낌입니다.
Non-Blocking / Async 조합은 자바스크립트에서 사용됩니다.
비동기 코드는 작업이 비동기적으로 실행 된다는 것입니다.
즉, 다른 작업이 완료될 때까지 기다리지 않고, 즉시 다음 작업을 수행할 수 있는 코드를 의미합니다.
비동기 코드를 작성하는 방법 중 하나는 CompletableFuture를 사용하는 것이라고 알게 되었습니다.
다음은 비동기 코드의 예시입니다:
import java.util.concurrent.CompletableFuture;
public class AsynchronousCodeExample {
public static void main(String[] args) {
System.out.println("시작");
// CompletableFuture를 사용하여 비동기 작업을 수행
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
// 비동기 작업 수행
System.out.println("비동기 작업이 실행됩니다.");
});
// 다른 작업을 수행할 수 있음
System.out.println("다른 작업을 수행합니다.");
// 비동기 작업이 완료될 때 실행할 콜백 등록
future.thenRun(() -> System.out.println("비동기 작업이 완료되었습니다."));
System.out.println("프로그램 종료");
}
}
``` 출력값
시작
다른 작업을 수행합니다.
비동기 작업이 실행됩니다.
비동기 작업이 완료되었습니다.
프로그램 종료
```
설명
위의 코드에서 CompletableFuture.runAsync()를 사용하여 비동기 작업을 시작하고,
thenRun()을 사용하여 비동기 작업이 완료될 때 실행할 후속 작업을 등록합니다.
이로 인해 비동기 작업이 완료될 때까지 기다리지 않고 다른 작업을 계속 수행할 수 있습니다.
블로킹(blocking) - 동기(synchronous)
Blocking의 관점은 제어권에 있고, 다른 작업이 진행되는 동안 자신의 작업을 처리하지 않습니다.
- 대표적인 예시)
- Scanner를 통해 입력을 받는 동안은 제어권이 넘어갔기 때문에 Blocking이고,
- 그 결과를 리턴받아서 다음의 작업을 바로 처리하고 있기 때문에 Sync 개념입니다.
논블로킹(non-blocking) - 비동기(asynchronous)
Non-Blocking은 다른 작업이 진행되는 동안에도 자신의 작업을 처리합니다.
그리고 Async이기 때문에 다른 작업의 결과 역시도 바로 처리하지 않아도 됩니다.
- 대표적인 예시로 자바스크립트에서 API 요청을 하고, 다른 작업을 하다가
- 콜백을 통해 추가적인 작업을 처리할 때 사용하는 것을 들 수 있습니다.
블로킹(blocking) - 비동기(asynchronous)
Blocking은 다른 작업이 진행되는 동안 자신의 작업을 처리하지 않습니다.
그리고 Async는 결과를 바로 처리하지 않아도 되는 것입니다.
- 가장 비효율적인 방법입니다.
- 개발자의 실수나 기타 이유로 이렇게 동작할 수도 있다고 합니다.
논블로킹(non-blocking) - 동기(synchronous)
Non-Blocking은 다른 작업이 있어도 자신의 작업을 처리하는 개념입니다.
Sync는 그 결과를 리턴 받았을 때 바로 그 결과에 집중하는 개념이었습니다.
B() 함수가 바로 제어권을 돌려주기에 A() 함수는 다른 작업을 수행할 수 있지만,
언제 종료되는지 알 수 없는 B() 함수의 종료를 A() 함수가 처리해야 합니다.
A() 함수가 직접 결과를 처리해야 하는 상황이기에
B() 함수의 종료를 반복적으로 물어봐야 하는 것입니다.
블로킹과 논블로킹의 차이
호출 받은 함수가 호출 했던 함수에게 제어권을 바로 주느냐 안주냐로 나뉠 수 있습니다
- 블로킹: 특정 작업이 완료될 때까지 다른 작업을 수행하지 않고 기다리는 방식입니다.
- 예를 들어, 파일을 읽는 동안 해당 작업이 완료될 때까지 다른 작업을 할 수 없습니다.
- 논블로킹: 특정 작업이 완료될 때까지 기다리지 않고 다른 작업을 계속 수행할 수 있는 방식입니다.
- 예를 들어, 파일을 읽는 동안 다른 작업을 계속 수행할 수 있습니다.
동기와 비동기의 차이
Sync / Async 는 호출한 함수와 호출 받은 함수 중에서 누가 return을 처리하는가 의 차이 입니다
- 동기: 작업이 순차적으로 실행되며, 이전 작업이 완료될 때까지 다음 작업이 시작되지 않습니다.
- 이해하기 쉽고 디버깅하기 용이하지만, 응답성이 떨어질 수 있습니다.
- 비동기: 작업이 비동기적으로 실행되어, 다른 작업이 완료될 때까지 기다리지 않고
즉시 다음 작업을 수행할 수 있습니다.- 응답성이 높고, 사용자 경험을 개선할 수 있습니다.
결론
동기와 비동기, 블로킹과 논블로킹의 개념을 이해하고 적절히 활용하면
프로그램의 성능과 응답성을 크게 향상시킬 수 있다는 것을 느꼈습니다.
Java에서는 CompletableFuture와 같은 도구를 통해 비동기 프로그래밍을
손쉽게 구현할 수 있었으며, 이를 통해 보다 효율적인 프로그램을 작성할 수 있습니다.
앞으로 다양한 상황에서 이 개념들을 적용해보며,
더욱 깊이 있는 예제를 통해 기술들을 적용할 수 있도록 하겠습니다.
'Java' 카테고리의 다른 글
자바와 스프링 프레임워크에서의 싱글톤 패턴과 전략 패턴 (0) | 2024.07.22 |
---|---|
컬렉션 프레임워크 설명 (0) | 2023.11.07 |
JVM 동작원리와 내부구조 (0) | 2023.11.07 |
JIT 컴파일러는 무엇인가요? (0) | 2023.11.07 |
배열의 선언과 메모리 할당 (0) | 2023.11.07 |