Many Java applications require of concurrent operations. When using concurrency there are common risk that have to be avoided such as memory leaking, race condition, callback hell, disjointed error handling…
In version 8, Java provides a new class CompletableFuture. This class has about 50 methods mainly for: compose, combine and execute asychronous steps and also to handle errors.
Concurrency classes provided by Java as Future and ExecutorService interfaces since version 5 to handle the asynchronous operations.
The Future interface is a placeholder for a result from an asynchronous operation which can be a Runnable or Callable instance.
The ExecutorService interface submits an asynchronous operation and returns a Future object.
The caller can use its get method to wait for the operation or cancel method to try to cancel the operation.
Future has the following methods:
isDone() : Checks if the computation is completed.
isCancelled() : checks if the task was cancelled before it is completed normally.
get() : blocks for its completion and to retrieve the result of the computation.
get(long timeout, TimeUnit unit) : blocks if necessary for at most the given time for this future to complete, and then returns its result, if available.
cancel() : cancels execution of this task if possible.
Java 8 Introduced a new Class for dealing with concurrency problems caused by Future like blockings, also implementing interfaces Runnable and CompletionStage.
Java 8 Concurrency new CompletonStage and CompletableFuture
Java 8 provided a new interface :
– java.util.concurrent.CompletionStage
This interface defines a “stage” of possible asynchronous computation. All its methods return an instance of “CompletionStage” itself. This way multiple Completionstages can be chained together to complete a group of tasks.
Java 8 also introduced a new class: a new
java.util.concurrent.CompletableFuture*
This class implements both: 1) Future and 2) CompletionStage interfaces. This class provides static methods as starting points of concurrent operations as we will see below.
Here are some of the more common used methods:
1) - supplyAsync(Supplier supplier) : Create a CompletableFuturence out of Suplier functional type.
2) runAsync(Runnable action) : Create a CompletableFuture instance out of Runnable functional type.
3) completeExceptionally(Throwable ex) : Return true if this invocation caused this CompletableFuture to transition to a completed state, else false.
4) thenRun(Runnable action) : Execute the action when it completes normally.
5) thenApply(Function f) : Return a new CompletionStage.
6) thenAccept(Consumer action) : Return a new CompletionStage.
7) thenCombine(Future fu, Function foo) : Combines a Future and a Function with two arguments to process both results.
8) thenCompose(Function f) : To chain two Futures sequentially.
.
Its important to understand how the new threads are obtained. In fact by default those threads are obtained from "ForkJoinPool.commonPool()", but we have also the possibility to create
our Executor (see: "Executors" API) and pass it to the CompletableFuture callbacks.
//Creating a new executor
Executor executor = Executors.newFixedThreadPool(5);
//then passing to CompletableFuture.supplyAsync(supplier, executor);
We can also launch new sync or async callback by calling "thenApply" operation. This callback offer to variants sync (same thread) or async(a new thread) -
package pub.Java.src;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class ExampleConcurrency {
public static void main(String[] args) {
/* Example of CompletableFuture */
/*First completable Future*/
CompletableFuture firstCompletableFuture = new CompletableFuture();
String s = "Is there someone? ";
String r = null;
try {
firstCompletableFuture.complete(": Yes! Hello Concurrent");;
r = firstCompletableFuture.get();
s = s + r;
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
System.out.println("Result: " + s);
/* "runAsync" : Example accepts a Runnable this time implemented with Anonymous Class */
CompletableFuture cfuture = new CompletableFuture().runAsync(new Runnable() {
@Override
public void run() {
String[] mesg = {"We","wait","in a" ,"different", "Thread"};
int i;
try {
for(i = 0;i cfuture1 = new CompletableFuture().runAsync( () ->
{
String[] mesg = {"We","wait","in a" ,"different", "Thread"};
int i;
try {
for(i = 0;i myLuckyNumberFuture = new CompletableFuture().supplyAsync(()->{
/* NOTE: STREAMS HAVE TO BE USED CAREFULLY IN CONCURRENT OPERATIONS
** In this case We need to use a Stream Supplier to get a new open Stream to invoke a new operation
* ONCE we have invoked a Terminal Operation (in this case ) that closes the Stream
* That is the way to AVOID the:" java.lang.IllegalStateException: stream has already been operated upon or closed"
* */
Supplier> supplierOfStreamNums = ()->Stream.of(0,1,2,3,4,5,6,7,8,9).parallel();
List luckList = supplierOfStreamNums.get().collect(Collectors.toList());
int ridx = (int) (Math.random()*10) % 10;
return (Integer) luckList.get(ridx);
});
/* We add the callback "thenApply" Function to modify the result obtained before */
myLuckyNumberFuture.thenApply((
l ->{
Integer n = l;
if(n%2==0)
n = n +1;
else
n = n -1;
return n;
}));
/* add callback "thenAccept" Consumer to consume the Integer generated, in this case by printing it */
myLuckyNumberFuture.thenAccept(n->System.out.println("My lucky number is (I'm in a different thread) : " + n));
//Invoking the blocking the CompletableFuture blocking operation "get" */
Integer myLuckyNumber = -1;
try {
myLuckyNumber = myLuckyNumberFuture.get();
System.out.println("My lucky number is : " + myLuckyNumber);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
Java 8 interface allows default implementations, static method declaration and static final attributes declarations:
Here we show an example (just to show the concept) of interface declaration and inheritance. We can add that with the default code, inherited attributes are hidden and we will show the final solution.
Example: In the code bellow we had to redeclare the inherited default method in each interface because the static attributes "from" and "to" were hidden by the super interface Locationable. You can try to remove the methods in subinterfaces to verify.
public interface Locationable {
float from = 0;
float to = 0;
public default int closeTo( float other) {
System.out.println(from + " and " + to );
if( other>=from && other<=to)
return 1;
return -1;
}
}
public interface Southern extends Locationable {
float from = 100;
float to = 1000;
public default int closeTo( float other) {
System.out.println(from + " and " + to );
if( other>=from && other<=to)
return 1;
return -1;
}
}
public interface Northern extends Locationable {
float from = 5000;
float to = 7000;
public default int closeTo( float other) {
System.out.println(from + " and " + to );
if( other>=from && other<=to)
return 1;
return -1;
}
}
public interface Midthern extends Locationable {
float from = 1000;
float to = 5000;
public default int closeTo( float other) {
System.out.println(from + " and " + to );
if( other>=from && other<=to)
return 1;
return -1;
}
}
public class Walker implements Southern,Northern,Midthern{
public int closeTo(float pos) {
int r = -1;
if( (Southern.super.closeTo(pos) == 1)) {
System.out.println("Hey I'm in the South!!");
r = 1;
}
else if( Northern.super.closeTo(pos) == 1) {
System.out.println("Hey I'm in the North!!");
r = 1;
}
else if( Midthern.super.closeTo(pos) == 1) {
System.out.println("Hey I'm in the Midlands!!");
r = 1;
}else
System.out.println("Hey I'm in the Lymbus!!!!");
return r;
}
}
void interfaces_exec() {
Walker walker = new Walker();
for(int i= 0; i < 20; i++) {
float pos = (float)(Math.random() * 7000) % 7000;
walker.closeTo(pos);
}
AI: Causal model and Rothman's model applied in bioscience
1.AI: Causal model
A causal model, or a model of causality, is a representation of a domain that predicts the results of interventions.
An intervention is an action that forces a variable to have a particular value.
That is, an intervention changes the value in some way other than manipulating other variables in the model.
To predict the effect of interventions, a causal model represents how the cause implies its effect.
When the cause is changed, its effect should be changed.
An evidential model represents a domain in the other direction – from effect to cause.
Note that we do not assume that there is “the cause” of an effect; rather there are propositions, which together may cause the effect to become true.
Example
In the electrical domain depicted in Figure 5.2, consider the relationship between poles p1 and p2 and alarm a1.
Assume all components are working properly. Alarm a1 sounds whenever both poles are + or both poles are -. Thus,
sounds_a1↔(+_p1 ⇔ +_p2) (*)
This is logically equivalent to +_p1↔(sounds_a1 ⇔ +_p2)
This formula is symmetric between the three propositions; it is true if and only if an odd number of the propositions are true.
However, in the world, the relationship between these propositions is not symmetric.
Suppose both poles were positive and the alarm sounded . Putting p1 to negative does not make p2 go negative to preserve a1 keep sounding.
Instead, putting p1 to negative makes sounds_a1 false, and positive_p2 remains true.
Thus, to predict the result of interventions, we require more than proposition (*) above.
The completion of this is equivalent to proposition (*); however, it makes reasonable predictions when one of the values is changed.
Changing one of the pole positions changes whether the alarm sounds, but changing whether the alarm sounds (by some other mechanism) does not change whether the poles are positive or negative.
This can be used to answer questions about whether p1 is + based on the charge of p2 and whether a1 sounds.
Its completion is also equivalent to formula (*).
However, it does not accurately predict the effect of interventions
For most purposes, it is preferable to use a causal model of the world as it is more transparent, stable and modular than an evidential model.
2. The Rothman's model (applied in biosciences)
Rothman’s model is a theoretical model that takes into account multi-causal relationship (has its origins on epimediology studies)
Definitions:
Cause: Event, condition or characteristic that plays an essential role in a generation of an effect (a consequence)
Cause types:
1- Component cause: A cause that contributes to generate a “conglomerate” that will produce a “Sufficient () cause” 2- Sufficient cause: A set of (component) causes that will produce an Effect 3- Necessary Cause: (To define)
Model characteristics:
I) None of the component causes is unnecessary
II) The Effect does not depend on a specific Sufficient Cause
III) A component cause can be part of more that one sufficient cause that produces the same Effect
IV) A component cause can be part of different sufficient causes that produces different Effects
V) The component causes of a sufficient cause are linked with other component causes of that sufficient cause (interelation)