Mastering Asynchronous Programming in Java: From Callbacks to User‑Level Threads
This article reviews why asynchronous programming is needed, explains continuations, compares callbacks, promises, reactive streams, async/await, and user‑level threads, and shows how each technique reduces I/O blocking and improves concurrency in Java applications.
When implementing asynchronous behavior in Java, the author revisits several classic and modern techniques, starting with the motivation for async: operating systems schedule threads transparently, but thread creation and context switches incur CPU and memory costs, so eliminating excessive threads is desirable.
Continuation
A continuation represents the remaining part of a computation as an object; the OS saves a thread's state during a context switch, which can be viewed as a continuation. By passing a continuation to a callee, the callee can resume the original computation after completing its work.
A function written in continuation‑passing style takes an extra argument: an explicit "continuation", i.e. a function of one argument. When the CPS function has computed its result value, it "returns" it by calling the continuation function with this value as the argument.
Callback (the naive async implementation)
In a blocking I/O model, a thread waits for a syscall such as recv() before proceeding. Asynchronous I/O replaces the wait with a callback that the event loop invokes once the operation completes, allowing the thread to continue other work.
var input = recv_from_socket(); // Block at syscall recv()
var result = calculator.calculate(input);
send_to_socket(result); // Block at syscall send()With async I/O, the callback is supplied when the request is issued:
recv_from_socket((input) -> {
var result = calculator.calculate(input);
send_to_socket(result); // ignore result
});Promise – a syntactic sugar over callbacks
Promises (Java's CompletableFuture or Guava's ListenableFuture) encapsulate an eventual result. They improve readability and allow chaining, while still representing an underlying continuation.
var promise_input = recv_from_socket();
promise_input.then((input) -> {
var result = calculator.calculate(input);
send_to_socket(result); // ignore result
});Reactive programming
Reactive extensions (Rx) extend promises by introducing streams (Observables) that can emit multiple values over time. Operators such as merge and debounce enable powerful composition, and back‑pressure mechanisms prevent overwhelming consumers.
CPS transformation: Coroutine and async/await
Languages like C#, JavaScript, and Python provide async/await, which the compiler rewrites into coroutine state machines via continuation‑passing style. This removes explicit callbacks from user code while preserving the underlying CPS transformation.
JVM also has an implementation: electronicarts/ea-async , which modifies bytecode at compile time to achieve a similar effect.
User‑level threads (the ultimate solution)
User‑level threading (e.g., Go's goroutines or Java's Quasar) discards OS threads for scheduling, running many lightweight threads on a small pool of kernel threads. Since scheduling occurs in user space, context‑switch overhead is dramatically reduced, and blocking system calls are intercepted by the runtime.
Conclusion
Promises and Reactive abstractions still rely on callbacks under the hood, whereas async/await and user‑level threads provide cleaner, more efficient models by moving CPS handling to the compiler or runtime. Java's native async support arrived late (CompletableFuture in Java 8), limiting ecosystem adoption, while projects like Quasar demonstrate the power of CPS‑based user‑level threading despite limited library support.
References
How long does it take to make a context switch?
ReactiveX
考不上三本也能给自己心爱的语言加上 Coroutine
Quasar
The Go scheduler
Callbacks VS Promises VS Async/Await
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Code Ape Tech Column
Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
