Async/Await
java2-5 covered concurrency the manual way — raw Thread, synchronized, thread pools. C# has a genuinely different, much higher-level answer for a large slice of that same territory, and it's the actual origin of syntax you may already recognize from JavaScript.
async/await Basics
async marks a method as containing suspension points; await marks each one. C# 5 (2012) introduced this exact syntax pattern as a real language feature — genuinely the origin, not a parallel invention: JavaScript's own async/await (ES2017, 2017) was explicitly modeled on C#'s design, five years later.
Task and Task<T>
Task (no result) and Task<T> (a future result) are what an async method returns — conceptually comparable to a JS Promise. This is a genuinely higher-level tool than anything java2-5 covered: Thread/Runnable/synchronized/java.util.concurrent are all real, manual thread-management primitives; Task-based async/await is a language feature built on top of that kind of machinery, not a replacement requiring the same manual bookkeeping.
What await Actually Does
await suspends the async method without blocking the calling thread — the thread is released to do other work, and the method resumes later via a continuation once the awaited Task completes. This is genuinely comparable to JavaScript's own event-loop-based async model, not java2-5's traditional blocking-thread model, where a thread sits idle (or is explicitly managed) while waiting.
async void — Fire-and-Forget, A Real Gotcha
async void exists specifically for event handlers, which can't return a Task due to the delegate signature they must match. A genuine, well-documented pitfall: an exception thrown inside an async void method can't be caught by its caller the normal way — it crashes the process instead of propagating as a catchable exception. Prefer async Task even for methods that logically return nothing.
Contrasted with java2-5's Concurrency Tools
java2-5's Thread/synchronized model is about managing real OS threads directly — genuinely necessary for CPU-bound parallel work. C#'s async/await is about something different: not blocking a thread while waiting on I/O (network calls, disk, database queries) — for pure I/O-bound work, no extra thread is used at all while awaiting. For genuine CPU-bound parallel work, C# has Task.Run(), which does use the thread pool — that's the territory actually comparable to java2-5's own material.
| Aspect | Java (java2-5) | C# | JavaScript |
|---|---|---|---|
| Model | manual Thread/synchronized | async/await, language-level | async/await, language-level |
| Blocks the calling thread while waiting | yes, by default | no — thread released during await | no — single-threaded event loop |
| Syntax arrival | n/a — thread APIs since Java 1.0 | C# 5 (2012) — the origin | ES2017 (2017) — modeled on C#'s |
Task.Run() specifically when genuine parallel CPU work is needed — that's the territory closest to java2-5's own thread-pool material. Plain async/await over I/O (network, disk, database) needs no extra thread at all while suspended.
async void method crashes the process rather than being catchable by the caller — a genuinely dangerous gotcha for code that looks completely ordinary at the call site. Use async Task everywhere except the one legitimate case: an event handler whose delegate signature requires void.
Coding Challenges
Write an async Task<int> method that awaits Task.Delay(500) and then returns 42, and call it with await from an async Main method, printing the result.
📄 View solutionWrite two async Task methods that each await a short delay and print a message, then call both without awaiting immediately (storing the returned Tasks), and finally await both together, demonstrating they ran concurrently rather than one after the other.
📄 View solutionWrite an async void method that throws an exception, call it, and show the caller cannot catch the exception with a normal try/catch around the call. Then rewrite it as async Task and show the exception CAN now be caught normally.
📄 View solutionChapter 4 Quick Reference
- async/await is real language syntax since C# 5 (2012) — the direct origin of JavaScript's own ES2017 async/await
- Task/Task<T> is what an async method returns — a much higher-level tool than java2-5's manual Thread/synchronized primitives
- await suspends without blocking the calling thread — the thread is released, resumed later via a continuation, closer to JS's event loop than Java's blocking-thread model
- async void is only for event handlers — exceptions inside it crash the process rather than being catchable; use async Task everywhere else
- Task.Run() is the genuine CPU-bound-parallelism tool, comparable to java2-5's own territory — plain async/await is for I/O-bound waiting, no extra thread needed
- Next chapter: records and pattern matching — C# 9 records, which genuinely shipped before java2-7's own Java 16 version