mirror of
https://github.com/tiennm99/java-design-patterns.git
synced 2026-10-14 06:17:55 +00:00
docs: improve guarded suspension
This commit is contained in:
1 parent
78e57a5490
commit
3d48f06980
4 files changed
+85
-35
No files matched your search
@@ -3,24 +3,27 @@ title: Guarded Suspension
|
||||
category: Concurrency
|
||||
language: en
|
||||
tag:
|
||||
- Decoupling
|
||||
- Asynchronous
|
||||
- Decoupling
|
||||
- Resource management
|
||||
- Synchronization
|
||||
- Thread management
|
||||
---
|
||||
|
||||
## Also known as
|
||||
|
||||
* Conditional Block
|
||||
* Suspended Execution
|
||||
|
||||
## Intent
|
||||
Use Guarded suspension pattern to handle a situation when you want to execute a method on object which is not in a proper state.
|
||||
|
||||
## Class diagram
|
||||

|
||||
|
||||
## Applicability
|
||||
Use Guarded Suspension pattern when the developer knows that the method execution will be blocked for a finite period of time
|
||||
The Guarded Suspension pattern manages operations that require both a lock and a condition to proceed, allowing a thread to wait for an appropriate condition while being efficient with resource use.
|
||||
|
||||
## Explanation
|
||||
|
||||
Real world example
|
||||
|
||||
> When we reserve a dining room online and arrive to find it unready, the manager has it cleaned while we wait.
|
||||
> Once ready, we're escorted to the room. This process exemplifies the Guarded Suspension pattern.
|
||||
> When we book a dining room online and arrive to find it not yet prepared, the manager arranges for it to be cleaned while we wait. Once the room is ready, we are then escorted to it. This scenario illustrates the Guarded Suspension pattern, where our access to the room is contingent upon a specific condition being met—namely, the room being cleaned.
|
||||
|
||||
In plain words
|
||||
|
||||
@@ -28,24 +31,23 @@ In plain words
|
||||
|
||||
Wikipedia says
|
||||
|
||||
> In concurrent programming, Guarded Suspension manages operations requiring a lock
|
||||
> and a precondition, delaying execution until the precondition is met.
|
||||
> In concurrent programming, Guarded Suspension manages operations requiring a lock and a precondition, delaying execution until the precondition is met.
|
||||
|
||||
**Programmatic Example**
|
||||
|
||||
The `GuardedQueue` class encapsulates a queue, and provides two synchronized methods, `get` and `put`.
|
||||
The `get` method waits if the queue is empty, and the `put` method adds an item to the queue and notifies waiting threads:
|
||||
The `GuardedQueue` class encapsulates a queue, and provides two synchronized methods, `get` and `put`. The `get` method waits if the queue is empty, and the `put` method adds an item to the queue and notifies waiting threads:
|
||||
|
||||
```java
|
||||
@Slf4j
|
||||
public class GuardedQueue {
|
||||
private final Queue<Integer> sourceList = new LinkedList<>();
|
||||
private final Queue<Integer> sourceList = new LinkedList<>();
|
||||
|
||||
public synchronized Integer get() {
|
||||
while (sourceList.isEmpty()) {
|
||||
try {
|
||||
wait();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
LOGGER.error("Error occurred: ", e);
|
||||
}
|
||||
}
|
||||
return sourceList.peek();
|
||||
@@ -56,11 +58,15 @@ private final Queue<Integer> sourceList = new LinkedList<>();
|
||||
notify();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Here is the `App` class driving the example.
|
||||
|
||||
```java
|
||||
public class App {
|
||||
public static void main(String[] args) {
|
||||
GuardedQueue guardedQueue = new GuardedQueue();
|
||||
ExecutorService executorService = Executors.newFixedThreadPool(3);
|
||||
public static void main(String[] args) {
|
||||
GuardedQueue guardedQueue = new GuardedQueue();
|
||||
ExecutorService executorService = Executors.newFixedThreadPool(3);
|
||||
|
||||
// Here we create the first thread which is supposed to get from guardedQueue
|
||||
executorService.execute(guardedQueue::get);
|
||||
@@ -68,7 +74,7 @@ ExecutorService executorService = Executors.newFixedThreadPool(3);
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
LOGGER.error("Error occurred: ", e);
|
||||
}
|
||||
|
||||
// Here we create the second thread which is supposed to put to guardedQueue
|
||||
@@ -80,13 +86,54 @@ ExecutorService executorService = Executors.newFixedThreadPool(3);
|
||||
try {
|
||||
executorService.awaitTermination(30, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
LOGGER.error("Error occurred: ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Executing the example yields:
|
||||
|
||||
## Related patterns
|
||||
```
|
||||
19:22:58.984 [pool-1-thread-1] INFO com.iluwatar.guarded.suspension.GuardedQueue -- waiting
|
||||
19:23:00.993 [pool-1-thread-2] INFO com.iluwatar.guarded.suspension.GuardedQueue -- putting
|
||||
19:23:00.994 [pool-1-thread-2] INFO com.iluwatar.guarded.suspension.GuardedQueue -- notifying
|
||||
19:23:00.994 [pool-1-thread-1] INFO com.iluwatar.guarded.suspension.GuardedQueue -- getting
|
||||
```
|
||||
|
||||
* Balking
|
||||
## Class diagram
|
||||
|
||||

|
||||
|
||||
## Applicability
|
||||
|
||||
This pattern is used in scenarios where a thread needs to wait for certain conditions to be met before it can proceed, ensuring that resources are utilized only when necessary and reducing the overhead of busy waiting.
|
||||
|
||||
## Known Uses
|
||||
|
||||
* Network servers waiting for client requests.
|
||||
* Producer-consumer scenarios where the consumer must wait for the producer to provide data.
|
||||
* Event-driven applications where actions are triggered only after specific events have occurred.
|
||||
|
||||
## Consequences
|
||||
|
||||
Benefits:
|
||||
|
||||
* Reduces CPU consumption by preventing busy waiting.
|
||||
* Increases system responsiveness by synchronizing actions to the availability of necessary conditions or resources.
|
||||
|
||||
Trade-offs:
|
||||
|
||||
* Complexity in implementation, especially when multiple conditions need to be managed.
|
||||
* Potential for deadlocks if not carefully managed.
|
||||
|
||||
## Related Patterns
|
||||
|
||||
* Monitor Object: Both patterns manage the synchronization of threads based on conditions. Guarded Suspension specifically deals with suspending threads until conditions are met, while Monitor Object encapsulates condition and mutual exclusion handling.
|
||||
* Producer-Consumer: Often implemented using Guarded Suspension to handle waiting consumers and producers efficiently.
|
||||
* Balking: Similar to Guarded Suspension, Balking is used when a thread checks a condition and only proceeds if the condition is favorable; if not, it immediately returns or bails out. This pattern complements Guarded Suspension by managing actions based on immediate condition checks without waiting.
|
||||
|
||||
## Credits
|
||||
|
||||
* [Java Concurrency in Practice](https://amzn.to/3JxnXek)
|
||||
* [Pattern-Oriented Software Architecture Volume 2: Patterns for Concurrent and Networked Objects](https://amzn.to/49Ke1c9)
|
||||
Reference in new issue
Block a user