import static java.util.concurrent.CompletableFuture.*
import java.util.concurrent.Executors
// ...
val ex = Executors.newCachedThreadPool
val isCancelled = new AtomicBoolean(false)
runAsync([
if(isCancelled.get) {
println("Oh no, I've been cancelled")
} else {
println("I'm fine")
}
], ex)
isCancelled.set(true)
Async Computations
Starting asynchronous computations and providing the result via a CompletableFuture
is
provided via the JDK methods CompletableFuture#runAsync
and CompletableFuture#suppyAsync
.
These methods have a few drawbacks. The first one is that in Xtend it is good practice to place the callback function as the last parameter in a parameter list to allow for more elegant and readable syntax, placing the lambda behind the closing parentheses. The JDK methods, however, have overloaded versions placing a executor for operation executor as last parameter.
The other drawback is that these methods need a further concept to allow cancellation of an operation
from the caller side, e.g. when the user cancels an operation. This can e.g. be achieved via an
additional java.util.concurrent.atomic.AtomicBoolean
which is passed to the operation.
This is unfortunate, since the CompletableFuture
already knows the concept of cancellation.
This library provides the class de.fhg.fokus.xtensions.concurrent.AsyncCompute
introducing
the methods asyncRun
and asyncSupply
. These methods allow asynchronous computations
like the JDK methods, but with a shuffled parameter list and passing the created CompletableFuture
into the operation to be computed asynchronously.
Example using JDK classes:
Same example using AsyncCompute
:
import static extension de.fhg.fokus.xtensions.concurrent.AsyncCompute.*
import java.util.concurrent.Executors
// ...
val pool = Executors.newCachedThreadPool
val fut = pool.asyncRun [
if(cancelled) {
println("Oh no, I've been cancelled")
} else {
println("I'm fine")
}
]
fut.cancel(false)
The asyncRun
and asyncSupply
methods have variants defining a timeout. If the provided actions
do not complete in the defined timeout, the returned future will be completed with a TimeoutException
.
The action should then check for completion of the future passed into it, instead of for cancellation.
Example:
asyncSupply(10, TimeUnit.MILLISECONDS) [
// some poor integration approximation
val fx = [double x| x*x + 10 - (2*x)]
var sum = 0.0d;
for(i : 0..100_000) {
// every now and then, check if we timed out
if(i % 100 == 0) {
if(done) {
return 0.0d;
}
}
// also using poor double accumulation
sum += fx.apply(i as double)
}
sum
].whenComplete[result, error |
if(error !== null) {
println("Whoops, timeout")
} else {
println("result = " + result)
}
]
Tip
|
Related JavaDocs: |