Compare commits

...

9 Commits

Author SHA1 Message Date
c2126bef76 #590 fix checkstyle error 2021-03-20 14:32:09 +02:00
468cb1ec27 #590 explanation for balking pattern 2021-03-20 14:11:16 +02:00
b5ed8b2278 labeling PR should trigger builds again for all-contributors bot (#1682) 2021-03-18 22:22:37 +02:00
8fc64a2d38 docs: add qfxl as a contributor (#1681)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2021-03-18 22:13:28 +02:00
7e91322a43 Add explanation to Async Method Invocation pattern (#1680)
* #590 make the example more interesting and add an explanation

* #590 fix checkstyle

Co-authored-by: Subhrodip Mohanta <hello@subho.xyz>
2021-03-18 11:07:34 +05:30
e9106ccfc5 fix spelling errors (#1679)
Co-authored-by: Subhrodip Mohanta <hello@subho.xyz>
2021-03-18 10:49:45 +05:30
77ffae5ecc Format active object README.md to display correctly on the web site 2021-03-14 16:26:24 +02:00
74abc7a0d6 added license headers to active object pattern (#1676) 2021-03-14 16:08:53 +02:00
ccf350b611 docs: add noamgrinch as a contributor (#1675)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2021-03-14 16:07:39 +02:00
13 changed files with 406 additions and 36 deletions

View File

@ -1422,6 +1422,24 @@
"contributions": [
"code"
]
},
{
"login": "noamgrinch",
"name": "Noam Greenshtain",
"avatar_url": "https://avatars.githubusercontent.com/u/31648669?v=4",
"profile": "https://github.com/noamgrinch",
"contributions": [
"code"
]
},
{
"login": "qfxl",
"name": "yonghong Xu",
"avatar_url": "https://avatars.githubusercontent.com/u/14086462?v=4",
"profile": "https://xuyonghong.cn/",
"contributions": [
"doc"
]
}
],
"contributorsPerLine": 4,

View File

@ -29,7 +29,7 @@ name: Java PR Builder
on:
pull_request:
branches: [ master ]
types: [ opened, reopened, synchronize ]
types: [ opened, reopened, synchronize, labeled, unlabeled ]
jobs:
build:

View File

@ -10,7 +10,7 @@
[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=iluwatar_java-design-patterns&metric=coverage)](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
[![Join the chat at https://gitter.im/iluwatar/java-design-patterns](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-156-orange.svg?style=flat-square)](#contributors-)
[![All Contributors](https://img.shields.io/badge/all_contributors-158-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
<br/>
@ -309,6 +309,10 @@ This project is licensed under the terms of the MIT license.
<td align="center"><a href="https://github.com/richardmr36"><img src="https://avatars.githubusercontent.com/u/19147333?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Martel Richard</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=richardmr36" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/va1m"><img src="https://avatars.githubusercontent.com/u/17025445?v=4?s=100" width="100px;" alt=""/><br /><sub><b>va1m</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=va1m" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/noamgrinch"><img src="https://avatars.githubusercontent.com/u/31648669?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Noam Greenshtain</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=noamgrinch" title="Code">💻</a></td>
<td align="center"><a href="https://xuyonghong.cn/"><img src="https://avatars.githubusercontent.com/u/14086462?v=4?s=100" width="100px;" alt=""/><br /><sub><b>yonghong Xu</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=qfxl" title="Documentation">📖</a></td>
</tr>
</table>
<!-- markdownlint-restore -->

View File

@ -79,12 +79,12 @@ public abstract class ActiveCreature{
return this.name;
}
}
```
We can see that any class that will extend the ActiveCreature class will have its own thread of control to execute and invocate methods.
For example, the Orc class:
```java
public class Orc extends ActiveCreature {
@ -96,6 +96,7 @@ public class Orc extends ActiveCreature {
```
Now, we can create multiple creatures such as Orcs, tell them to eat and roam and they will execute it on their own thread of control:
```java
public static void main(String[] args) {
var app = new App();
@ -121,4 +122,4 @@ Now, we can create multiple creatures such as Orcs, tell them to eat and roam an
## Class diagram
![alt text](./etc/active-object.urm.png "Active Object class diagram")
![alt text](./etc/active-object.urm.PNG "Active Object class diagram")

View File

@ -1,3 +1,26 @@
/*
* The MIT License
* Copyright © 2014-2021 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.activeobject;
import java.util.concurrent.BlockingQueue;

View File

@ -1,3 +1,26 @@
/*
* The MIT License
* Copyright © 2014-2021 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.activeobject;
/**

View File

@ -1,3 +1,26 @@
/*
* The MIT License
* Copyright © 2014-2021 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.activeobject;
import static org.junit.jupiter.api.Assertions.assertEquals;

View File

@ -1,3 +1,26 @@
/*
* The MIT License
* Copyright © 2014-2021 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.activeobject;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;

View File

@ -9,21 +9,160 @@ tags:
---
## Intent
Asynchronous method invocation is pattern where the calling thread
Asynchronous method invocation is a pattern where the calling thread
is not blocked while waiting results of tasks. The pattern provides parallel
processing of multiple independent tasks and retrieving the results via
callbacks or waiting until everything is done.
## Explanation
Real world example
> Launching space rockets is an exciting business. The mission command gives an order to launch and
> after some undetermined time, the rocket either launches successfully or fails miserably.
In plain words
> Asynchronous method invocation starts task processing and returns immediately before the task is
> ready. The results of the task processing are returned to the caller later.
Wikipedia says
> In multithreaded computer programming, asynchronous method invocation (AMI), also known as
> asynchronous method calls or the asynchronous pattern is a design pattern in which the call site
> is not blocked while waiting for the called code to finish. Instead, the calling thread is
> notified when the reply arrives. Polling for a reply is an undesired option.
**Programmatic Example**
In this example, we are launching space rockets and deploying lunar rovers.
The application demonstrates the async method invocation pattern. The key parts of the pattern are
`AsyncResult` which is an intermediate container for an asynchronously evaluated value,
`AsyncCallback` which can be provided to be executed on task completion and `AsyncExecutor` that
manages the execution of the async tasks.
```java
public interface AsyncResult<T> {
boolean isCompleted();
T getValue() throws ExecutionException;
void await() throws InterruptedException;
}
```
```java
public interface AsyncCallback<T> {
void onComplete(T value, Optional<Exception> ex);
}
```
```java
public interface AsyncExecutor {
<T> AsyncResult<T> startProcess(Callable<T> task);
<T> AsyncResult<T> startProcess(Callable<T> task, AsyncCallback<T> callback);
<T> T endProcess(AsyncResult<T> asyncResult) throws ExecutionException, InterruptedException;
}
```
`ThreadAsyncExecutor` is an implementation of `AsyncExecutor`. Some of its key parts are highlighted
next.
```java
public class ThreadAsyncExecutor implements AsyncExecutor {
@Override
public <T> AsyncResult<T> startProcess(Callable<T> task) {
return startProcess(task, null);
}
@Override
public <T> AsyncResult<T> startProcess(Callable<T> task, AsyncCallback<T> callback) {
var result = new CompletableResult<>(callback);
new Thread(
() -> {
try {
result.setValue(task.call());
} catch (Exception ex) {
result.setException(ex);
}
},
"executor-" + idx.incrementAndGet())
.start();
return result;
}
@Override
public <T> T endProcess(AsyncResult<T> asyncResult)
throws ExecutionException, InterruptedException {
if (!asyncResult.isCompleted()) {
asyncResult.await();
}
return asyncResult.getValue();
}
}
```
Then we are ready to launch some rockets to see how everything works together.
```java
public static void main(String[] args) throws Exception {
// construct a new executor that will run async tasks
var executor = new ThreadAsyncExecutor();
// start few async tasks with varying processing times, two last with callback handlers
final var asyncResult1 = executor.startProcess(lazyval(10, 500));
final var asyncResult2 = executor.startProcess(lazyval("test", 300));
final var asyncResult3 = executor.startProcess(lazyval(50L, 700));
final var asyncResult4 = executor.startProcess(lazyval(20, 400), callback("Deploying lunar rover"));
final var asyncResult5 =
executor.startProcess(lazyval("callback", 600), callback("Deploying lunar rover"));
// emulate processing in the current thread while async tasks are running in their own threads
Thread.sleep(350); // Oh boy, we are working hard here
log("Mission command is sipping coffee");
// wait for completion of the tasks
final var result1 = executor.endProcess(asyncResult1);
final var result2 = executor.endProcess(asyncResult2);
final var result3 = executor.endProcess(asyncResult3);
asyncResult4.await();
asyncResult5.await();
// log the results of the tasks, callbacks log immediately when complete
log("Space rocket <" + result1 + "> launch complete");
log("Space rocket <" + result2 + "> launch complete");
log("Space rocket <" + result3 + "> launch complete");
}
```
Here's the program console output.
```java
21:47:08.227 [executor-2] INFO com.iluwatar.async.method.invocation.App - Space rocket <test> launched successfully
21:47:08.269 [main] INFO com.iluwatar.async.method.invocation.App - Mission command is sipping coffee
21:47:08.318 [executor-4] INFO com.iluwatar.async.method.invocation.App - Space rocket <20> launched successfully
21:47:08.335 [executor-4] INFO com.iluwatar.async.method.invocation.App - Deploying lunar rover <20>
21:47:08.414 [executor-1] INFO com.iluwatar.async.method.invocation.App - Space rocket <10> launched successfully
21:47:08.519 [executor-5] INFO com.iluwatar.async.method.invocation.App - Space rocket <callback> launched successfully
21:47:08.519 [executor-5] INFO com.iluwatar.async.method.invocation.App - Deploying lunar rover <callback>
21:47:08.616 [executor-3] INFO com.iluwatar.async.method.invocation.App - Space rocket <50> launched successfully
21:47:08.617 [main] INFO com.iluwatar.async.method.invocation.App - Space rocket <10> launch complete
21:47:08.617 [main] INFO com.iluwatar.async.method.invocation.App - Space rocket <test> launch complete
21:47:08.618 [main] INFO com.iluwatar.async.method.invocation.App - Space rocket <50> launch complete
```
# Class diagram
![alt text](./etc/async-method-invocation.png "Async Method Invocation")
## Applicability
Use async method invocation pattern when
Use the async method invocation pattern when
* You have multiple independent tasks that can run in parallel
* You need to improve the performance of a group of sequential tasks
* You have limited amount of processing capacity or long running tasks and the
caller should not wait the tasks to be ready
* You have a limited amount of processing capacity or long-running tasks and the caller should not wait for the tasks to be ready
## Real world examples

View File

@ -27,10 +27,12 @@ import java.util.concurrent.Callable;
import lombok.extern.slf4j.Slf4j;
/**
* This application demonstrates the async method invocation pattern. Key parts of the pattern are
* <code>AsyncResult</code> which is an intermediate container for an asynchronously evaluated
* value, <code>AsyncCallback</code> which can be provided to be executed on task completion and
* <code>AsyncExecutor</code> that manages the execution of the async tasks.
* In this example, we are launching space rockets and deploying lunar rovers.
*
* <p>The application demonstrates the async method invocation pattern. The key parts of the
* pattern are <code>AsyncResult</code> which is an intermediate container for an asynchronously
* evaluated value, <code>AsyncCallback</code> which can be provided to be executed on task
* completion and <code>AsyncExecutor</code> that manages the execution of the async tasks.
*
* <p>The main method shows example flow of async invocations. The main thread starts multiple
* tasks with variable durations and then continues its own work. When the main thread has done it's
@ -68,13 +70,14 @@ public class App {
final var asyncResult1 = executor.startProcess(lazyval(10, 500));
final var asyncResult2 = executor.startProcess(lazyval("test", 300));
final var asyncResult3 = executor.startProcess(lazyval(50L, 700));
final var asyncResult4 = executor.startProcess(lazyval(20, 400), callback("Callback result 4"));
final var asyncResult4 = executor.startProcess(lazyval(20, 400),
callback("Deploying lunar rover"));
final var asyncResult5 =
executor.startProcess(lazyval("callback", 600), callback("Callback result 5"));
executor.startProcess(lazyval("callback", 600), callback("Deploying lunar rover"));
// emulate processing in the current thread while async tasks are running in their own threads
Thread.sleep(350); // Oh boy I'm working hard here
log("Some hard work done");
Thread.sleep(350); // Oh boy, we are working hard here
log("Mission command is sipping coffee");
// wait for completion of the tasks
final var result1 = executor.endProcess(asyncResult1);
@ -84,9 +87,9 @@ public class App {
asyncResult5.await();
// log the results of the tasks, callbacks log immediately when complete
log("Result 1: " + result1);
log("Result 2: " + result2);
log("Result 3: " + result3);
log("Space rocket <" + result1 + "> launch complete");
log("Space rocket <" + result2 + "> launch complete");
log("Space rocket <" + result3 + "> launch complete");
}
/**
@ -99,7 +102,7 @@ public class App {
private static <T> Callable<T> lazyval(T value, long delayMillis) {
return () -> {
Thread.sleep(delayMillis);
log("Task completed with: " + value);
log("Space rocket <" + value + "> launched successfully");
return value;
};
}
@ -115,7 +118,7 @@ public class App {
if (ex.isPresent()) {
log(name + " failed: " + ex.map(Exception::getMessage).orElse(""));
} else {
log(name + ": " + value);
log(name + " <" + value + ">");
}
};
}

View File

@ -9,19 +9,131 @@ tags:
---
## Intent
Balking Pattern is used to prevent an object from executing certain code if it is an
incomplete or inappropriate state
Balking Pattern is used to prevent an object from executing a certain code if it is in an incomplete
or inappropriate state.
## Explanation
Real world example
> There's a start-button in a washing machine to initiate the laundry washing. When the washing
> machine is inactive the button works as expected, but if it's already washing the button does
> nothing.
In plain words
> Using the balking pattern, a certain code executes only if the object is in particular state.
Wikipedia says
> The balking pattern is a software design pattern that only executes an action on an object when
> the object is in a particular state. For example, if an object reads ZIP files and a calling
> method invokes a get method on the object when the ZIP file is not open, the object would "balk"
> at the request.
**Programmatic Example**
In this example implementation, `WashingMachine` is an object that has two states in which it can
be: ENABLED and WASHING. If the machine is ENABLED, the state changes to WASHING using a thread-safe
method. On the other hand, if it already has been washing and any other thread executes `wash()`
it won't do that and returns without doing anything.
Here are the relevant parts of the `WashingMachine` class.
```java
@Slf4j
public class WashingMachine {
private final DelayProvider delayProvider;
private WashingMachineState washingMachineState;
public WashingMachine(DelayProvider delayProvider) {
this.delayProvider = delayProvider;
this.washingMachineState = WashingMachineState.ENABLED;
}
public WashingMachineState getWashingMachineState() {
return washingMachineState;
}
public void wash() {
synchronized (this) {
var machineState = getWashingMachineState();
LOGGER.info("{}: Actual machine state: {}", Thread.currentThread().getName(), machineState);
if (this.washingMachineState == WashingMachineState.WASHING) {
LOGGER.error("Cannot wash if the machine has been already washing!");
return;
}
this.washingMachineState = WashingMachineState.WASHING;
}
LOGGER.info("{}: Doing the washing", Thread.currentThread().getName());
this.delayProvider.executeAfterDelay(50, TimeUnit.MILLISECONDS, this::endOfWashing);
}
public synchronized void endOfWashing() {
washingMachineState = WashingMachineState.ENABLED;
LOGGER.info("{}: Washing completed.", Thread.currentThread().getId());
}
}
```
Here's the simple `DelayProvider` interface used by the `WashingMachine`.
```java
public interface DelayProvider {
void executeAfterDelay(long interval, TimeUnit timeUnit, Runnable task);
}
```
Now we introduce the application using the `WashingMachine`.
```java
public static void main(String... args) {
final var washingMachine = new WashingMachine();
var executorService = Executors.newFixedThreadPool(3);
for (int i = 0; i < 3; i++) {
executorService.execute(washingMachine::wash);
}
executorService.shutdown();
try {
executorService.awaitTermination(10, TimeUnit.SECONDS);
} catch (InterruptedException ie) {
LOGGER.error("ERROR: Waiting on executor service shutdown!");
Thread.currentThread().interrupt();
}
}
```
Here is the console output of the program.
```
14:02:52.268 [pool-1-thread-2] INFO com.iluwatar.balking.WashingMachine - pool-1-thread-2: Actual machine state: ENABLED
14:02:52.272 [pool-1-thread-2] INFO com.iluwatar.balking.WashingMachine - pool-1-thread-2: Doing the washing
14:02:52.272 [pool-1-thread-3] INFO com.iluwatar.balking.WashingMachine - pool-1-thread-3: Actual machine state: WASHING
14:02:52.273 [pool-1-thread-3] ERROR com.iluwatar.balking.WashingMachine - Cannot wash if the machine has been already washing!
14:02:52.273 [pool-1-thread-1] INFO com.iluwatar.balking.WashingMachine - pool-1-thread-1: Actual machine state: WASHING
14:02:52.273 [pool-1-thread-1] ERROR com.iluwatar.balking.WashingMachine - Cannot wash if the machine has been already washing!
14:02:52.324 [pool-1-thread-2] INFO com.iluwatar.balking.WashingMachine - 14: Washing completed.
```
## Class diagram
![alt text](./etc/balking.png "Balking")
## Applicability
Use the Balking pattern when
* you want to invoke an action on an object only when it is in a particular state
* objects are generally only in a state that is prone to balking temporarily
but for an unknown amount of time
* You want to invoke an action on an object only when it is in a particular state
* Objects are generally only in a state that is prone to balking temporarily but for an unknown
amount of time
## Related patterns
* Guarded Suspension Pattern
* Double Checked Locking Pattern
* [Guarded Suspension Pattern](https://java-design-patterns.com/patterns/guarded-suspension/)
* [Double Checked Locking Pattern](https://java-design-patterns.com/patterns/double-checked-locking/)
## Credits
* [Patterns in Java: A Catalog of Reusable Design Patterns Illustrated with UML, 2nd Edition, Volume 1](https://www.amazon.com/gp/product/0471227293/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0471227293&linkId=0e39a59ffaab93fb476036fecb637b99)

View File

@ -32,11 +32,11 @@ import lombok.extern.slf4j.Slf4j;
* then the method will return without doing anything. Objects that use this pattern are generally
* only in a state that is prone to balking temporarily but for an unknown amount of time
*
* <p>In this example implementation WashingMachine is an object that has two states in which it
* can be: ENABLED and WASHING. If the machine is ENABLED the state is changed into WASHING that any
* other thread can't invoke this action on this and then do the job. On the other hand if it have
* been already washing and any other thread execute wash() it can't do that once again and returns
* doing nothing.
* <p>In this example implementation, {@link WashingMachine} is an object that has two states in
* which it can be: ENABLED and WASHING. If the machine is ENABLED, the state changes to WASHING
* using a thread-safe method. On the other hand, if it already has been washing and any other
* thread executes {@link WashingMachine#wash()} it won't do that and returns without doing
* anything.
*/
@Slf4j
public class App {
@ -54,11 +54,12 @@ public class App {
}
executorService.shutdown();
try {
executorService.awaitTermination(10, TimeUnit.SECONDS);
if (!executorService.awaitTermination(10, TimeUnit.SECONDS)) {
executorService.shutdownNow();
}
} catch (InterruptedException ie) {
LOGGER.error("ERROR: Waiting on executor service shutdown!");
Thread.currentThread().interrupt();
}
}
}

View File

@ -105,7 +105,7 @@ Program output:
```java
This is Ford.
This Ferrari.
This is Ferrari.
```
## Class Diagram