mirror of
https://github.com/tiennm99/java-design-patterns.git
synced 2026-09-02 14:20:28 +00:00
docs: Update Async Method Invocation documentation
This commit is contained in:
@@ -3,7 +3,9 @@ title: Async Method Invocation
|
|||||||
category: Concurrency
|
category: Concurrency
|
||||||
language: en
|
language: en
|
||||||
tag:
|
tag:
|
||||||
|
- Asynchronous
|
||||||
- Reactive
|
- Reactive
|
||||||
|
- Scalability
|
||||||
---
|
---
|
||||||
|
|
||||||
## Intent
|
## Intent
|
||||||
@@ -13,6 +15,10 @@ is not blocked while waiting results of tasks. The pattern provides parallel
|
|||||||
processing of multiple independent tasks and retrieving the results via
|
processing of multiple independent tasks and retrieving the results via
|
||||||
callbacks or waiting until everything is done.
|
callbacks or waiting until everything is done.
|
||||||
|
|
||||||
|
## Also known as
|
||||||
|
|
||||||
|
* Asynchronous Procedure Call
|
||||||
|
|
||||||
## Explanation
|
## Explanation
|
||||||
|
|
||||||
Real world example
|
Real world example
|
||||||
@@ -158,13 +164,42 @@ Here's the program console output.
|
|||||||
|
|
||||||
Use the async method invocation pattern when
|
Use the async method invocation pattern when
|
||||||
|
|
||||||
* You have multiple independent tasks that can run in parallel
|
* When operations do not need to complete before proceeding with the next steps in a program.
|
||||||
* You need to improve the performance of a group of sequential tasks
|
* For tasks that are resource-intensive or time-consuming, such as IO operations, network requests, or complex computations, where making the operation synchronous would significantly impact performance or user experience.
|
||||||
* You have a limited amount of processing capacity or long-running tasks and the caller should not wait for the tasks to be ready
|
* In GUI applications to prevent freezing or unresponsiveness during long-running tasks.
|
||||||
|
* In web applications for non-blocking IO operations.
|
||||||
|
|
||||||
## Real world examples
|
## Known Uses
|
||||||
|
|
||||||
|
* Web servers handling HTTP requests asynchronously to improve throughput and reduce latency.
|
||||||
|
* Desktop and mobile applications using background threads to perform time-consuming operations without blocking the user interface.
|
||||||
|
* Microservices architectures where services perform asynchronous communications via messaging queues or event streams.
|
||||||
* [FutureTask](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/FutureTask.html)
|
* [FutureTask](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/FutureTask.html)
|
||||||
* [CompletableFuture](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html)
|
* [CompletableFuture](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html)
|
||||||
* [ExecutorService](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html)
|
* [ExecutorService](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html)
|
||||||
* [Task-based Asynchronous Pattern](https://msdn.microsoft.com/en-us/library/hh873175.aspx)
|
* [Task-based Asynchronous Pattern](https://msdn.microsoft.com/en-us/library/hh873175.aspx)
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
Benefits:
|
||||||
|
|
||||||
|
* Improved Responsiveness: The main thread or application flow remains unblocked, improving the user experience in GUI applications and overall responsiveness.
|
||||||
|
* Better Resource Utilization: By enabling parallel execution, system resources (like CPU and IO) are utilized more efficiently, potentially improving the application's throughput.
|
||||||
|
* Scalability: Easier to scale applications, as tasks can be distributed across available resources more effectively.
|
||||||
|
|
||||||
|
Trade-offs:
|
||||||
|
|
||||||
|
* Complexity: Introducing asynchronous operations can complicate the codebase, making it more challenging to understand, debug, and maintain.
|
||||||
|
* Resource Management: Requires careful management of threads or execution contexts, which can introduce overhead and potential resource exhaustion issues.
|
||||||
|
* Error Handling: Asynchronous operations can make error handling more complex, as exceptions may occur in different threads or at different times.
|
||||||
|
|
||||||
|
Related Patterns:
|
||||||
|
|
||||||
|
* [Command](https://java-design-patterns.com/patterns/command/): Asynchronous method invocation can be used to implement the Command pattern, where commands are executed asynchronously.
|
||||||
|
* [Observer](https://java-design-patterns.com/patterns/observer/): Asynchronous method invocation can be used to notify observers asynchronously when a subject's state changes.
|
||||||
|
* [Promise](https://java-design-patterns.com/patterns/promise/): The AsyncResult interface can be considered a form of Promise, representing a value that may not be available yet.
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
|
||||||
|
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3Ti1N4f)
|
||||||
|
* [Java Concurrency in Practice](https://amzn.to/4ab97VU)
|
||||||
|
|||||||
+8
-8
@@ -75,7 +75,7 @@ class ThreadAsyncExecutorTest {
|
|||||||
* Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable)}
|
* Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable)}
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testSuccessfulTaskWithoutCallback() throws Exception {
|
void testSuccessfulTaskWithoutCallback() {
|
||||||
assertTimeout(ofMillis(3000), () -> {
|
assertTimeout(ofMillis(3000), () -> {
|
||||||
// Instantiate a new executor and start a new 'null' task ...
|
// Instantiate a new executor and start a new 'null' task ...
|
||||||
final var executor = new ThreadAsyncExecutor();
|
final var executor = new ThreadAsyncExecutor();
|
||||||
@@ -101,7 +101,7 @@ class ThreadAsyncExecutorTest {
|
|||||||
* AsyncCallback)}
|
* AsyncCallback)}
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testSuccessfulTaskWithCallback() throws Exception {
|
void testSuccessfulTaskWithCallback() {
|
||||||
assertTimeout(ofMillis(3000), () -> {
|
assertTimeout(ofMillis(3000), () -> {
|
||||||
// Instantiate a new executor and start a new 'null' task ...
|
// Instantiate a new executor and start a new 'null' task ...
|
||||||
final var executor = new ThreadAsyncExecutor();
|
final var executor = new ThreadAsyncExecutor();
|
||||||
@@ -134,7 +134,7 @@ class ThreadAsyncExecutorTest {
|
|||||||
* task takes a while to execute
|
* task takes a while to execute
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testLongRunningTaskWithoutCallback() throws Exception {
|
void testLongRunningTaskWithoutCallback() {
|
||||||
assertTimeout(ofMillis(5000), () -> {
|
assertTimeout(ofMillis(5000), () -> {
|
||||||
// Instantiate a new executor and start a new 'null' task ...
|
// Instantiate a new executor and start a new 'null' task ...
|
||||||
final var executor = new ThreadAsyncExecutor();
|
final var executor = new ThreadAsyncExecutor();
|
||||||
@@ -174,7 +174,7 @@ class ThreadAsyncExecutorTest {
|
|||||||
* AsyncCallback)} when a task takes a while to execute
|
* AsyncCallback)} when a task takes a while to execute
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testLongRunningTaskWithCallback() throws Exception {
|
void testLongRunningTaskWithCallback() {
|
||||||
assertTimeout(ofMillis(5000), () -> {
|
assertTimeout(ofMillis(5000), () -> {
|
||||||
// Instantiate a new executor and start a new 'null' task ...
|
// Instantiate a new executor and start a new 'null' task ...
|
||||||
final var executor = new ThreadAsyncExecutor();
|
final var executor = new ThreadAsyncExecutor();
|
||||||
@@ -222,7 +222,7 @@ class ThreadAsyncExecutorTest {
|
|||||||
* ThreadAsyncExecutor#endProcess(AsyncResult)}
|
* ThreadAsyncExecutor#endProcess(AsyncResult)}
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testEndProcess() throws Exception {
|
void testEndProcess() {
|
||||||
assertTimeout(ofMillis(5000), () -> {
|
assertTimeout(ofMillis(5000), () -> {
|
||||||
// Instantiate a new executor and start a new 'null' task ...
|
// Instantiate a new executor and start a new 'null' task ...
|
||||||
final var executor = new ThreadAsyncExecutor();
|
final var executor = new ThreadAsyncExecutor();
|
||||||
@@ -259,7 +259,7 @@ class ThreadAsyncExecutorTest {
|
|||||||
* the callable is 'null'
|
* the callable is 'null'
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testNullTask() throws Exception {
|
void testNullTask() {
|
||||||
assertTimeout(ofMillis(3000), () -> {
|
assertTimeout(ofMillis(3000), () -> {
|
||||||
// Instantiate a new executor and start a new 'null' task ...
|
// Instantiate a new executor and start a new 'null' task ...
|
||||||
final var executor = new ThreadAsyncExecutor();
|
final var executor = new ThreadAsyncExecutor();
|
||||||
@@ -286,7 +286,7 @@ class ThreadAsyncExecutorTest {
|
|||||||
* AsyncCallback)} when the callable is 'null', but the asynchronous callback is provided
|
* AsyncCallback)} when the callable is 'null', but the asynchronous callback is provided
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testNullTaskWithCallback() throws Exception {
|
void testNullTaskWithCallback() {
|
||||||
assertTimeout(ofMillis(3000), () -> {
|
assertTimeout(ofMillis(3000), () -> {
|
||||||
// Instantiate a new executor and start a new 'null' task ...
|
// Instantiate a new executor and start a new 'null' task ...
|
||||||
final var executor = new ThreadAsyncExecutor();
|
final var executor = new ThreadAsyncExecutor();
|
||||||
@@ -322,7 +322,7 @@ class ThreadAsyncExecutorTest {
|
|||||||
* AsyncCallback)} when both the callable and the asynchronous callback are 'null'
|
* AsyncCallback)} when both the callable and the asynchronous callback are 'null'
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testNullTaskWithNullCallback() throws Exception {
|
void testNullTaskWithNullCallback() {
|
||||||
assertTimeout(ofMillis(3000), () -> {
|
assertTimeout(ofMillis(3000), () -> {
|
||||||
// Instantiate a new executor and start a new 'null' task ...
|
// Instantiate a new executor and start a new 'null' task ...
|
||||||
final var executor = new ThreadAsyncExecutor();
|
final var executor = new ThreadAsyncExecutor();
|
||||||
|
|||||||
Reference in New Issue
Block a user