«En langage Java, j'ai pensé:« Je veux écrire un traitement asynchrone et un traitement parallèle avec une grammaire ** JavaScript Promise-like ** </ font> ». --La source est dans le référentiel suivant https://github.com/riversun/java-promise
Comment écrire le processus «Lorsque ** le processus asynchrone 1 ** est terminé, ** le processus asynchrone 2 ** est exécuté en utilisant le résultat» en Java?
--Solution 1: Solution à l'ère de Java 1.4: faites de votre mieux avec la fonction de classe Thread --Maintenir les threads de manière imbriquée ou attendre la fin avec jointure. L'aube du traitement parallèle. --Solution 2: Solution à l'ère Java5 (1.5): je me demande si j'étais satisfait de Callable / Future ... Je suis heureux que vous puissiez renvoyer le résultat avec Future / Callable, et en plus, j'ai tous les accessoires tels que semapho et latch, mais je dois faire de mon mieux. --Solution 3: Solution à l'ère de Java 8: Vous devriez être satisfait de Completable Future. --Enfin, le mécanisme de pattern Future / Promise tant attendu est maintenant disponible en standard!
Dans cet article, j'ai écrit le code suivant à la manière d'une promesse JavaScript dans une perspective différente de celle des trois solutions ci-dessus.
Exemple de promesse en Java
Promise.resolve()
.then((action, data) -> {
//Traitement asynchrone 1
new Thread(() -> {System.out.println("Process1");action.resolve("Result-1");}).start();
})
.then((action, data) -> {
//Traitement asynchrone 2
new Thread(() -> {System.out.println("Process2");action.resolve("Result-2");}).start();
})
.start();
-Réalisation du modèle Future / Promise (académique)
--Java 5 ou version ultérieure
Il se trouve dans le référentiel Maven en tant que bibliothèque ** java-promise **, vous pouvez donc l'utiliser immédiatement en ajoutant ce qui suit.
Maven
POM.dépendance xml
<dependency>
<groupId>org.riversun</groupId>
<artifactId>java-promise</artifactId>
<version>1.1.0</version>
</dependency>
Gradle
build.gradle
dependencies {
compile 'org.riversun:java-promise:1.1.0'
}
build.gradle(Android)
dependencies {
implementation 'org.riversun:java-promise:1.1.0'
}
** Tout d'abord, rédigez une promesse en JavaScript pour comparaison **
Le code suivant est un [exemple] JavaScript (https://developer.mozilla.org/en-US/docs/) qui concatène simplement le résultat du traitement exécuté de manière asynchrone («bar») à la chaîne «foo». Code Web / JavaScript / Référence / Global_Objects / Promise / puis # Chaining). Extrait de ce qui est publié comme exemple de Promise dans MDN.
Example.js
Promise.resolve('foo')
.then(function (data) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
const newData = data + 'bar';
resolve(newData);
}, 1);
});
})
.then(function (data) {
return new Promise(function (resolve, reject) {
console.log(data);
resolve();
});
});
console.log("Promise in JavaScript");
Le résultat de l'exécution est le suivant
Promise in JavaScript
foobar
** Ensuite, écrivez en utilisant java-promise dans Java 8 **
Example.java
import org.riversun.promise.Promise;
public class Example {
public static void main(String[] args) {
Promise.resolve("foo")
.then(new Promise((action, data) -> {
new Thread(() -> {
String newData = data + "bar";
action.resolve(newData);//#Passer au processus suivant avec résolution
}).start();//Exécuter dans un thread séparé
}))
.then(new Promise((action, data) -> {
System.out.println(data);
action.resolve();
}))
.start();//Déclencheur pour démarrer le traitement
System.out.println("Promise in Java");
}
}
Le résultat de l'exécution est le suivant
Promise in Java
foobar
Puisque l'exécution ci-dessous Promise est effectuée de manière asynchrone (thread séparé), vous pouvez voir que System.out.println (" Promise in Java ");
est exécuté dans cet exemple.
Pour faciliter le traitement, j'ai essayé de me rapprocher de la syntaxe de JavaScript de type Promise, sauf que j'ai appelé .start ()
à la fin pour déclencher la chaîne Promise.
Si vous n'utilisez pas l'expression lambda, ce sera comme suit
Lorsqu'il est écrit sans utiliser l'expression lambda
Promise.resolve("foo")
.then(new Promise(new Func() {
@Override
public void run(Action action, Object data) throws Exception {
new Thread(() -> {
String newData = data + "bar";
action.resolve(newData);
}).start();
}
}))
.then(new Promise(new Func() {
@Override
public void run(Action action, Object data) throws Exception {
new Thread(() -> {
System.out.println(data);
action.resolve();
}).start();
}
}))
.start();
L'identité de la partie où (action, données) -> {}
est l'interface qui représente la fonction en JavaScript.
Func.java
public interface Func {
public void run(Action action, Object data) throws Exception;
}
Vous pouvez utiliser Promise.then (new Func ())
au lieu de Promise.then (new Promise ())
. Si vous remplacez new Func
par une expression lambda, cela devient Promise.then ((action, data) -> {})
, ce qui le rend encore plus simple.
then(Func)Écrire en utilisant
Promise.resolve("foo")
.then((action, data) -> {
new Thread(() -> {
String newData = data + "bar";
action.resolve(newData);
}).start();
})
.then((action, data) -> {
System.out.println(data);
action.resolve();
})
.start();
code:
public class Example20 {
public static void main(String[] args) {
//Processus 1 (exécution d'un autre thread)
Func function1 = (action, data) -> {
new Thread(() -> {
System.out.println("Process-1");
Promise.sleep(1000);// Thread.Identique au sommeil
action.resolve("Result-1");//Statut"fulfilled"Et le résultat dans le processus suivant("Result-1")Dire
}).start();//Démarrer le traitement asynchrone dans un autre thread
};
//Processus 2
Func function2 = (action, data) -> {
System.out.println("Process-2 result=" + data);
action.resolve();
};
Promise.resolve()//Commencer le traitement
.then(function1)//Exécution du processus 1
.then(function2)//Exécution du processus 2
.start();//début
System.out.println("Hello,Promise");
}
** Résultat d'exécution: **
Hello,Promise
Process-1
Process-2 result=Result-1
La description: La grammaire de ** then ** est ** Promise.then (onFulfilled [, onRejected]); ** Autrement dit, cela peut prendre jusqu'à deux arguments. Le premier argument ** onFulfilled ** est exécuté si l'exécution précédente s'est terminée avec le statut rempli (≒ réussi) </ font>. Le deuxième argument ** onRejected ** est facultatif, mais il sera exécuté si l'exécution précédente s'est terminée avec le statut rejeté (≒ échoué) </ font>. Cet exemple spécifie uniquement le premier argument.
** Flux de traitement: **
code:
public class Example21 {
public static void main(String[] args) {
Func function1 = (action, data) -> {
System.out.println("Process-1");
action.reject();//Statut"rejected"Définir et terminer l'exécution
};
Func function2_1 = (action, data) -> {
System.out.println("Resolved Process-2");
action.resolve();
};
Func function2_2 = (action, data) -> {
System.out.println("Rejected Process-2");
action.resolve();
};
Promise.resolve()
.then(function1)
.then(
function2_1, //Exécuté lorsque le statut est rempli
function2_2 //Exécuté lorsque le statut est rejeté
)
.start();
System.out.println("Hello,Promise");
}
}
** Résultat d'exécution: **
Hello,Promise
Process-1
Rejected Process-2
La description:
** function1 ** est
action.reject();
Puisqu'il est complété par, l'état sera rejeté </ font>. Le prochain ** alors ** est
.then(
function2_1, //Exécuté lorsque le statut est rempli
function2_2 //Exécuté lorsque le statut est rejeté
)
C'est dit. Comme mentionné ci-dessus, la syntaxe de ** then ** est ** Promise.then (onFulfilled [, onRejected]); **, donc Puisque l'état d'achèvement de ** fonction1 ** est rejeté </ font>, ** function2_2 **, qui est le deuxième argument de ** puis **, est exécuté ici.
** Flux de traitement: **
code:
public class Example30 {
public static void main(String[] args) {
Func function1 = (action, data) -> {
action.reject("I send REJECT");
};
Func function2 = (action, data) -> {
System.out.println("Received:" + data);
action.resolve();
};
Promise.resolve()
.then(function1)
.always(function2)//Le statut est"fulfilled"Mais"rejected"Mais実行される
.start();
}
}
** Résultat d'exécution: **
Received:I send REJECT
La description:
.always(function2)
** always ((action, data) -> {}) ** a un statut <couleur de la police en raison de rejet, même si le processus précédent avait un statut accompli </ font> en raison de la résolution. Toujours exécuté indépendamment de = rouge> rejeté </ font>.
** Flux de traitement: **
code:
public class Example40 {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
//Traitement asynchrone 1
Func function1 = (action, data) -> {
new Thread(() -> {
Promise.sleep(1000); System.out.println("func1 running");action.resolve("func1-result");
}).start();
};
//Traitement asynchrone 2
Func function2 = (action, data) -> {
new Thread(() -> {
Promise.sleep(500);System.out.println("func2 running"); action.resolve("func2-result");
}).start();
};
//Traitement asynchrone 3
Func function3 = (action, data) -> {
new Thread(() -> {
Promise.sleep(100);System.out.println("func3 running");action.resolve("func3-result");
}).start();
};
//Le processus pour finalement recevoir le résultat
Func function4 = (action, data) -> {
System.out.println("Reçu le résultat");
List<Object> resultList = (List<Object>) data;
for (int i = 0; i < resultList.size(); i++) {
Object result = resultList.get(i);
System.out.println("Traitement asynchrone" + (i + 1) + "Le résultat de" + result);
}
action.resolve();
};
Promise.all(function1, function2, function3)
.always(function4)
.start();
}
}
** Résultat d'exécution: **
func3 running
func2 running
func1 running
Reçu le résultat du traitement asynchrone
Le résultat du processus asynchrone 1 est func1-result
Le résultat du traitement asynchrone 2 est func2-result
Le résultat du traitement asynchrone 3 est func3-result
La description:
--Lorsque l'exécution parallèle est terminée, le processus passe à la chaîne ** puis ** (ici ** toujours **). --Dans l'exemple ci-dessus, ** function1, function2, function3 ** sont exécutés en parallèle, mais si ** function1 à function3 ** sont tous complétés par rempli </ font>, chacun * Les résultats de * function1 à function3 ** sont stockés dans ** List ** et transmis à ** then **. A ce moment-là, l'ordre de stockage est l'ordre de ** fonction1, fonction2, fonction3 ** spécifié dans l'argument. (Cette spécification est également la même que la promesse JavaScript)
** Flux de traitement: **
Comme expliqué dans (4), ** Func ** peut être utilisé en parallèle avec ** Promise.all **, mais ** Executor ** est utilisé comme politique de création de thread lors de l'exécution d'une opération parallèle à l'avance. Peut être défini. De plus, le pool de threads déjà préparé à une autre fin peut être détourné vers ** Promise.all **.
** Exemple de code: **
public class Example41 {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
final ExecutorService myExecutor = Executors.newFixedThreadPool(2);
//Traitement asynchrone 1
Func function1 = (action, data) -> {
System.out.println("No.1 " + Thread.currentThread());
new Thread(() -> {
Promise.sleep(1000);System.out.println("func1 running");action.resolve("func1-result");
}).start();
};
//Traitement asynchrone 2
Func function2 = (action, data) -> {
System.out.println("No.2 " + Thread.currentThread());
new Thread(() -> {
Promise.sleep(500);System.out.println("func2 running");action.resolve("func2-result");
}).start();
};
//Traitement asynchrone 3
Func function3 = (action, data) -> {
System.out.println("No.3 " + Thread.currentThread());
new Thread(() -> {
Promise.sleep(100);System.out.println("func3 running");action.resolve("func3-result");
}).start();
};
//Le processus pour finalement recevoir le résultat
Func function4 = (action, data) -> {
System.out.println("No.4 final " + Thread.currentThread());
System.out.println("Reçu le résultat");
List<Object> resultList = (List<Object>) data;
for (int i = 0; i < resultList.size(); i++) {
Object result = resultList.get(i);
System.out.println("Traitement asynchrone" + (i + 1) + "Le résultat de" + result);
}
myExecutor.shutdown();
action.resolve();
};
Promise.all(myExecutor, function1, function2, function3)
.always(function4)
.start();
}
}
** Résultat d'exécution: **
No.1 Thread[pool-1-thread-2,5,main]
No.2 Thread[pool-1-thread-2,5,main]
No.3 Thread[pool-1-thread-2,5,main]
func3 running
func2 running
func1 running
No.4 final Thread[pool-1-thread-1,5,main]
Reçu le résultat
Le résultat du processus asynchrone 1 est func1-result
Le résultat du traitement asynchrone 2 est func2-result
Le résultat du traitement asynchrone 3 est func3-result
Les résultats montrent que ** Func ** s'exécute sur des threads provenant du même pool de threads. (Étant donné que le traitement asynchrone (nouveau Thread) est intentionnellement effectué dans Func, le traitement asynchrone est en dehors du pool de threads spécifié.)
La description:
-Définissez le ** Executor ** utilisé pour exécuter ** Promise.all **. Vous trouverez ci-dessous un pool de threads avec une taille de pool de 2.
final ExecutorService myExecutor = Executors.newFixedThreadPool(2);
Promise.all(myExecutor, function1, function2, function3)
.always(function4)
.start();
--Si vous spécifiez ** Executor ** vous-même, n'oubliez pas de ** arrêter **
Func function4 = (action, data) -> {
//Omission
myExecutor.shutdown();
action.resolve();
};
** Politique de filetage: **
git clone https: // github.com / Riversun / java-promise.git
--mvn test
vous donnera un test unitaire.--En outre, l'exemple de code publié dans cet article est ci-dessous. https://github.com/riversun/java-promise-examples/tree/master-ja
Recommended Posts