실제 코드로 비교했습니다. 코루틴은 non-blocking으로 효율적이고, 자바 스레드는 blocking으로 리소스 소모가 큽니다. 아래에 각 상황별 코드를 나란히 보여드릴게요.
1. 네트워크 API 호출 (서버 통신) – 콜백 지옥 vs 순차적 코드
자바 방식 (콜백 지옥 예시 – Retrofit enqueue)
api.getPosts(new Callback<List<Post>>() {
@Override
public void onResponse(Call<List<Post>> call, Response<List<Post>> response) {
api.getUsers(new Callback<List<User>>() {
@Override
public void onResponse(Call<List<User>> call, Response<List<User>> response2) {
// 중첩 깊어짐... 에러 처리도 복잡
}
@Override public void onFailure(...) { ... }
});
}
@Override public void onFailure(...) { ... }
});
코루틴 방식 (순차적처럼 보임)
viewModelScope.launch {
try {
val posts = api.getPosts() // suspend – 대기하지만 non-blocking
val users = api.getUsers()
// 자연스럽게 순차 처리
} catch (e: Exception) {
// 한 곳에서 에러 처리
}
}
→ 코루틴이 훨씬 가독성 좋고 에러 처리 간단!
2. 병렬 작업 (여러 API 동시에 호출)
자바 방식 (ThreadPool + Future)
ExecutorService executor = Executors.newFixedThreadPool(2);
Future<String> future1 = executor.submit(() -> { Thread.sleep(1000); return "작업1"; });
Future<String> future2 = executor.submit(() -> { Thread.sleep(1000); return "작업2"; });
String result = future1.get() + future2.get(); // blocking 대기
executor.shutdown();
코루틴 방식 (async/await)
val deferred1 = async { delay(1000); "작업1" }
val deferred2 = async { delay(1000); "작업2" }
val result = deferred1.await() + deferred2.await() // non-blocking
→ 소요 시간 거의 동일 (~1초), 하지만 코루틴 코드가 더 간결하고 스레드 관리 자동.
3. 대량 동시 작업 (예: 10,000개 요청)
자바 스레드 → 스레드 하나당 ~1-2MB 메모리 소모 → 10,000개 생성 시 OutOfMemoryError 발생 확률 높음.
코루틴 → 경량 (몇 KB) → 스레드 몇 개로 수만 개 처리 가능.
이 차이가 서버-클라이언트에서 가장 크게 체감됩니다 (고동시 네트워크 요청 처리 시 코루틴이 압승).
4. 안드로이드 UI 업데이트
자바 방식 (잘못된 예 – 메인 스레드 블로킹)
new Thread(() -> {
// 네트워크 호출 (blocking)
runOnUiThread(() -> updateUI());
}).start();
코루틴 방식
viewModelScope.launch(Dispatchers.IO) {
val data = api.fetch() // 백그라운드
withContext(Dispatchers.Main) {
updateUI(data) // 자동 UI 스레드 전환
}
}
→ ANR(앱 멈춤) 방지 완벽.
요약: 코드로 직접 비교해보면 코루틴이 더 간결하고 안전하며 확장성 좋음을 알 수 있어요. 특히 I/O 많은 서버-클라이언트 시나리오에서 빛납니다! 실제 프로젝트에서 한 번 써보시면 차이 확 느껴질 거예요 😊
답글 남기기