Skip to content
tezvyn:

Top 30 Coroutines Interview Questions and Answers

30 multiple-choice questions on Coroutines, drawn from 30 bites out of the 46 tagged Coroutines on Tezvyn. Answer them here or read straight down. Every question carries the correct option, why it is correct, and a link to the bite it came from.

30 questions. Pick an answer, or open “Show the answer” to read it.

Answers are graded in your browser. Nothing is saved, and no XP or streak is earned here. The app keeps score.

  1. Question 1 of 30

    What is the immediate result of calling a function defined with async def, like my_coro(), without awaiting it?

    Show the answer

    Answer: c · A coroutine object is returned, which must be explicitly run by an event loop.

    Calling an async def function directly only creates a coroutine object; it does not execute the function's code. This object must then be awaited or scheduled with an event loop to run. Option B describes synchronous function behavior, and Option A incorrectly implies immediate background execution without the necessary explicit step.

    Read the full bite: Python Coroutines: Functions You Can Pause and Resume

  2. Question 2 of 30

    When running a background task that might fail, how do you defer exception handling until the result is actually needed?

    Show the answer

    Answer: d · Use `async` and wrap the call to `await()` in a `try-catch` block.

    `async` encapsulates any exception, which is re-thrown only when `await()` is called, allowing for deferred handling. In contrast, `launch` propagates exceptions immediately, so a `CoroutineExceptionHandler` would trigger right away.

    Read the full bite: Difference between launch and async in Kotlin Coroutines

  3. Question 3 of 30

    For a Kotlin Coroutine task that updates a UI element and does not require a return value, which builder is most appropriate?

    Show the answer

    Answer: d · launch

    The correct choice is launch because it is designed for 'fire-and-forget' operations, such as UI updates, where a direct result is not needed and it returns a Job. Using async for such a task would create a Deferred object whose result is never awaited, potentially leading to silently swallowed exceptions.

    Read the full bite: Explain launch vs. async in Kotlin Coroutines

  4. Question 4 of 30

    You need to fetch two pieces of data in parallel inside a ViewModel and return both results to the caller. Which choice best follows structured concurrency?

    Show the answer

    Answer: a · Use async for both calls and await each Deferred before returning

    async returns a Deferred that lets you retrieve computed values with await, which is exactly what you need when results must be returned, whereas launch is fire-and-forget. Option C is tempting but wrong because injecting a custom Job breaks the parent-child relationship required by structured concurrency.

    Read the full bite: Explain the difference between launch and async in Kotlin Coroutines

  5. Question 5 of 30

    What is the primary effect of a `suspend` function when it needs to wait for a long-running operation like a network request?

    Show the answer

    Answer: b · It can pause the coroutine's execution, freeing the underlying thread to perform other work.

    A suspend function pauses the coroutine, freeing the thread it was running on for other work. It does not inherently switch threads (that's a dispatcher's job) or block the thread.

    Read the full bite: What is a `suspend` function in Kotlin?

  6. Question 6 of 30

    Which statement accurately describes the Kotlin language rule for calling a suspend function?

    Show the answer

    Answer: a · It is only permitted from another suspend function or a coroutine builder.

    Kotlin enforces that suspend functions run inside a coroutine context, so they can only be called from another suspend function or a builder like launch or async. Option C is tempting because runBlocking is a valid bridge from regular code, but it is not required for every invocation.

    Read the full bite: What is a suspend function in Kotlin and its compiler rules?

  7. Question 7 of 30

    What is the fundamental mechanism enabling a Kotlin suspend function to pause execution without blocking its calling thread?

    Show the answer

    Answer: d · The compiler transforms it into a state machine using Continuation-Passing Style.

    The correct answer is B because the card explicitly states the compiler performs a transformation called Continuation-Passing Style (CPS), which creates a state machine allowing the function to pause and resume. Option C is a common misconception; suspend functions do not inherently move execution to a background thread, as suspension is orthogonal to threading.

    Read the full bite: What is a Kotlin `suspend` function and how does it work?

  8. Question 8 of 30

    Which statement best describes why Dispatchers.Unconfined is generally discouraged for common use cases?

    Show the answer

    Answer: d · Its behavior after a suspending function can lead to unpredictable thread execution.

    Dispatchers.Unconfined is discouraged because it starts on the current thread but can resume on any thread used by a suspending function, leading to unpredictable execution. This is distinct from creating new threads (which is more relevant to newSingleThreadContext) or always running on the main thread.

    Read the full bite: Coroutine Dispatchers: Telling Your Coroutines Which Thread to Use

  9. Question 9 of 30

    Which behavior correctly describes exception propagation for a coroutine launched with launch inside a regular Job scope?

    Show the answer

    Answer: c · The exception propagates to the parent, which cancels siblings and fails the scope.

    Under a regular Job, a failing child propagates its exception upward, causing the parent to cancel all siblings and fail the scope. Distractor D describes SupervisorJob behavior, which must be explicitly used to prevent sibling cancellation.

    Read the full bite: How does Structured Concurrency handle cancellations and exceptions?

  10. Question 10 of 30

    What is the primary effect of cancelling a CoroutineScope?

    Show the answer

    Answer: b · All coroutines that were launched within that scope are automatically cancelled.

    The core function of a CoroutineScope is to manage the lifecycle of its child coroutines; thus, cancelling the scope automatically cancels all coroutines launched within it. Option C is incorrect because existing coroutines are also cancelled, not continued, and new launches would fail rather than just being prevented.

    Read the full bite: CoroutineScope: The Parent of Your Coroutines

  11. Question 11 of 30

    In a standard CoroutineScope, if one child coroutine fails with an exception, what is the immediate effect on its siblings and the parent scope?

    Show the answer

    Answer: b · The failing coroutine cancels its siblings, and the exception then propagates up to cancel the parent scope.

    Structured concurrency with a standard Job follows an 'all-for-one' policy. An uncaught exception in one child cancels its siblings and then propagates to the parent, cancelling the entire scope. The behavior where siblings continue running is characteristic of a SupervisorJob.

    Read the full bite: Structured Concurrency in Kotlin Coroutines

  12. Question 12 of 30

    In Kotlin's Structured Concurrency, what is the default outcome if one child coroutine launched with launch throws an uncaught exception?

    Show the answer

    Answer: b · The parent scope and all its sibling coroutines are immediately cancelled.

    With a default Job, an uncaught exception in a child coroutine launched with 'launch' propagates up, cancelling the parent scope and all its other children, ensuring a "fail-fast" system. Option A is incorrect because the default behavior is not to isolate failures but to propagate them, unlike with a SupervisorJob.

    Read the full bite: Explain Structured Concurrency in Kotlin Coroutines

  13. Question 13 of 30

    What happens if a Kotlin Flow is created but no terminal operator like .collect() is invoked?

    Show the answer

    Answer: b · The Flow's producer code will not execute, and no values will be emitted.

    Flows are 'cold,' meaning their producer code only executes when a terminal operator like .collect() is called. Without a collector, the flow builder block never runs, so no values are emitted. Option C is incorrect because nothing is emitted to be discarded.

    Read the full bite: Kotlin Flow: Asynchronous Data Streams

  14. Question 14 of 30

    Why is `StateFlow` preferred over a cold `Flow` in a ViewModel for exposing UI state that must survive screen rotation?

    Show the answer

    Answer: c · A cold `Flow` would re-execute its data production logic for the new UI after rotation, while `StateFlow` holds the existing state.

    `StateFlow` is a hot, state-holding stream. It maintains its value across UI recreations, providing the latest state to the new UI. A cold `Flow` would restart its producer logic for the new UI collector, causing an unnecessary data reload. The most tempting distractor is the lifecycle-awareness claim, which is true for `LiveData`, not `StateFlow`.

    Read the full bite: Hot vs. Cold Streams: `StateFlow` vs. `Flow`

  15. Question 15 of 30

    Why should a ViewModel use StateFlow instead of a cold Flow for screen state?

    Show the answer

    Answer: d · It broadcasts the latest state to all current collectors without re-running the upstream source for each one

    StateFlow is hot and always holds a current value, so multiple collectors share the same state and receive the latest value immediately without re-triggering the data load. Option B describes cold Flow behavior, which would execute duplicate upstream work for every collector.

    Read the full bite: Hot vs cold Kotlin Flows and StateFlow use case

  16. Question 16 of 30

    Why is StateFlow generally preferred over a regular Flow for exposing UI state from an Android ViewModel?

    Show the answer

    Answer: b · It always holds a current value, replays it to new collectors immediately, and prevents re-execution of upstream logic on re-collection.

    StateFlow is ideal for UI state because it always maintains a current value, immediately provides this value to new observers, and critically, avoids re-triggering the entire data stream (e.g., network calls) when the UI re-collects, such as after a screen rotation. Option A is a common misconception, as StateFlow is not inherently lifecycle-aware and requires explicit scope management for collection.

    Read the full bite: Hot vs. Cold Streams: StateFlow vs. Flow in Android

  17. Question 17 of 30

    An Android ViewModel reads a large file from disk and parses the bytes into objects. Which dispatcher strategy is correct?

    Show the answer

    Answer: b · Perform the read on Dispatchers.IO and the parsing on Dispatchers.Default

    Blocking file reads should use Dispatchers.IO, while CPU-intensive parsing belongs on Dispatchers.Default. Using Default for the read starves its limited thread pool, and using IO for parsing misuses the on-demand thread expansion designed for blocking operations.

    Read the full bite: What is a CoroutineDispatcher and when to use Default versus IO?

  18. Question 18 of 30

    Which problem does Kotlin's Structured Concurrency primarily aim to solve?

    Show the answer

    Answer: d · Preventing resource leaks from uncancelled background tasks.

    Structured concurrency's main purpose is to enforce lifetime management for concurrent work, preventing resource leaks and unnecessary work by ensuring background tasks are cancelled when no longer needed. While other options are valid concurrency concerns, they are not the primary problem addressed by structured concurrency itself.

    Read the full bite: Structured Concurrency in Kotlin

  19. Question 19 of 30

    When applying a complex image filter and then uploading the image, which CoroutineDispatchers are best for each task?

    Show the answer

    Answer: a · Filter on Dispatchers.Default, upload on Dispatchers.IO

    Applying a complex filter is CPU-bound and best suited for Dispatchers.Default, which uses a core-limited thread pool. Uploading is I/O-bound and should use Dispatchers.IO, designed for blocking operations with a larger, on-demand thread pool. Using Dispatchers.IO for CPU-bound tasks is inefficient and doesn't leverage the CPU-optimized Default pool.

    Read the full bite: What is a CoroutineDispatcher and when to use IO vs Default?

  20. Question 20 of 30

    Your coroutine performs a blocking network call. Which dispatcher is most suitable to ensure CPU-bound tasks are not starved of their dedicated threads?

    Show the answer

    Answer: d · Dispatchers.IO

    Dispatchers.IO is backed by a large thread pool designed for blocking I/O. Using Dispatchers.Default would block a thread from a smaller pool sized for CPU-intensive work, starving computation.

    Read the full bite: What is a CoroutineDispatcher and when do you use each type?

  21. Question 21 of 30

    What is the key distinction in how a child coroutine's termination impacts its parent Job?

    Show the answer

    Answer: a · An unhandled exception from a child cancels the parent, while a child's normal cancellation does not.

    The card states that if a child Job fails with an exception (other than CancellationException), it cancels its parent. However, if a child is cancelled normally via cancel() (which uses CancellationException), it does not affect the parent.

    Read the full bite: Kotlin's Job: A Handle to a Background Task

  22. Question 22 of 30

    For which scenario is Kotlin's async/await pattern the most appropriate choice?

    Show the answer

    Answer: c · Fetching a user's profile and their friends list concurrently from different API endpoints.

    The card states that async/await is for running multiple independent, long-running tasks concurrently and combining their results, as exemplified by fetching data from different API endpoints. Option B describes an anti-pattern, as async/await is not for sequential, dependent operations.

    Read the full bite: Kotlin Coroutines: async/await for Parallel Results

  23. Question 23 of 30

    Which statement accurately distinguishes the backpressure behavior of buffer(), conflate(), and collectLatest() in Kotlin Flow?

    Show the answer

    Answer: d · buffer() suspends the emitter when full, conflate() silently drops intermediate values, and collectLatest() cancels the active collector

    buffer() suspends the producer when its Channel is full rather than dropping values, conflate() silently discards intermediate emissions while the collector runs, and collectLatest() cancels the active collection block on each new emission. Option B is tempting because it uses the correct vocabulary but assigns the behaviors to the wrong operators.

    Read the full bite: How do buffer, conflate, and collectLatest manage Kotlin Flow backpressure?

  24. Question 24 of 30

    When processing a rapid stream of UI events, where each event triggers an expensive, cancellable background task, which Flow operator ensures only the latest event's task runs, cancelling any prior in-progress tasks?

    Show the answer

    Answer: c · collectLatest()

    collectLatest() is designed to cancel the processing block for a previous item if a new one is emitted, restarting the operation with the latest data. In contrast, conflate() only drops intermediate values, ensuring the collector receives the most recent value, but it does not cancel any long-running work already initiated for a prior item.

    Read the full bite: Explain backpressure in Kotlin Flows and its management operators

  25. Question 25 of 30

    A Flow emits frequent updates, but the collector's work is slow. To ensure resources are only spent on the latest item by cancelling work on stale ones, which approach is best?

    Show the answer

    Answer: c · Use `collectLatest()` to cancel the collector's current work block as soon as a new item is emitted from the producer.

    `collectLatest` is correct because it cancels the collector's ongoing work when a new value arrives, preventing wasted resources on stale data. `conflate` is a common misconception; it drops values on the producer side but does not cancel any ongoing work in the collector.

    Read the full bite: Explain backpressure in Kotlin Flows and its management operators

  26. Question 26 of 30

    A coroutine executes a CPU-intensive `while` loop without any suspend function calls. If its job is cancelled, what is required for the coroutine to actually stop?

    Show the answer

    Answer: a · The loop must periodically check the `isActive` property of the coroutine context and manually exit.

    Coroutine cancellation is cooperative, not preemptive. For code without suspension points, like a tight loop, the coroutine must manually check its `isActive` state to participate in cancellation.

    Read the full bite: How does coroutine cancellation work internally?

  27. Question 27 of 30

    Why does a CPU-intensive while-loop inside a coroutine ignore job.cancel() and keep running?

    Show the answer

    Answer: d · The loop never hits a suspension point where the coroutine checks its Job state

    Kotlin coroutine cancellation is cooperative, so a tight loop without suspension points never checks the Job's cancelling state and continues running. Distractor B is wrong because cancel() does not forcibly interrupt the underlying thread; it only sets a flag that standard suspend functions check at suspension points.

    Read the full bite: Describe coroutine cancellation mechanics and cooperative suspend functions

  28. Question 28 of 30

    Which statement accurately describes how job.cancel() influences a running coroutine?

    Show the answer

    Answer: b · It sets a flag, causing cooperative suspend functions or explicit isActive checks to throw a CancellationException.

    The correct answer (B) reflects that cancellation is cooperative: job.cancel() sets a flag, and the coroutine itself must check this flag (via suspend functions or isActive) to throw a CancellationException. Option (D) is a common misconception, as coroutine cancellation does not directly stop the underlying thread; it's an abstraction above threads.

    Read the full bite: How does coroutine cancellation work internally?

  29. Question 29 of 30

    What is the primary reason StateFlow is generally not recommended for handling one-time UI events like showing a Snackbar?

    Show the answer

    Answer: a · Its state-holding nature can cause the event to be re-emitted upon UI re-collection (e.g., config change).

    StateFlow is a state-holder that always provides the current value. If used for one-shot events, its state-holding nature means that a UI re-collection (e.g., after a configuration change) would re-receive the last "event" state, causing the event to trigger again. Options A, B, and D describe incorrect characteristics of StateFlow.

    Read the full bite: StateFlow: A Hot Flow for UI State

  30. Question 30 of 30

    An exception occurs inside an `async` block. The `Deferred` result is stored, but `await()` is never called on it. What happens to the exception?

    Show the answer

    Answer: b · It is caught and held within the `Deferred` object, and program execution continues.

    `async` catches its own exceptions and stores them in the `Deferred` result. The exception is only re-thrown when `await()` is called. Option C describes the behavior of `launch`, a common point of confusion.

    Read the full bite: Coroutine Exception Handling: launch vs. async

Could you explain these out loud?

That is what an interview actually tests. Tezvyn gives you questions like these with what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.

The iPhone app is on the way

We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.

Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.

Get it on Google PlayiPhone app coming soon