――In der Java-Sprache dachte ich: "Ich möchte asynchrone Verarbeitung und parallele Verarbeitung mit ** JavaScript Promise-like ** </ font> Grammatik schreiben."
Wie soll ich den Prozess "Wenn ** asynchroner Prozess 1 ** beendet ist, ** asynchroner Prozess 2 ** mit dem Ergebnis ausgeführt wird" in Java schreiben?
――In diesem Artikel habe ich den folgenden Code in einer JavaScript Promise-ähnlichen Weise aus einer anderen Perspektive als die oben genannten drei Lösungen geschrieben.
Versprechen Sie Beispiel in Java
Promise.resolve()
.then((action, data) -> {
//Asynchrone Verarbeitung 1
new Thread(() -> {System.out.println("Process1");action.resolve("Result-1");}).start();
})
.then((action, data) -> {
//Asynchrone Verarbeitung 2
new Thread(() -> {System.out.println("Process2");action.resolve("Result-2");}).start();
})
.start();
――Was Sie tun möchten, ist ** "In JavaScript Promise-like schreiben" ** </ font>
-Realisierung des (akademischen) Zukunfts- / Versprechensmusters
Es befindet sich im Maven-Repository als Bibliothek ** Java-Versprechen **, sodass Sie es sofort verwenden können, indem Sie Folgendes hinzufügen.
Maven
POM.XML-Abhängigkeit
<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'
}
** Schreiben Sie zuerst ein Versprechen in JavaScript zum Vergleich **
Der folgende Code ist ein JavaScript Beispiel, das das asynchron ausgeführte Verarbeitungsergebnis ('bar') einfach mit dem String 'foo' verknüpft. Web / JavaScript / Referenz / Global_Objects / Promise / then # Chaining) Code. Dies ist ein Auszug aus dem als Beispiel für Promise in [MDN] veröffentlichten (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then#Chaining).
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");
Das Ausführungsergebnis ist wie folgt
Promise in JavaScript
foobar
** Als nächstes schreiben Sie mit Java-Versprechen in 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);//#Fahren Sie mit Entschlossenheit zum nächsten Prozess fort
}).start();//In einem separaten Thread ausführen
}))
.then(new Promise((action, data) -> {
System.out.println(data);
action.resolve();
}))
.start();//Auslöser zum Starten der Verarbeitung
System.out.println("Promise in Java");
}
}
Das Ausführungsergebnis ist wie folgt
Promise in Java
foobar
Da die Ausführung unter Promise asynchron ausgeführt wird (separater Thread), können Sie sehen, dass in diesem Beispiel System.out.println (" Promise in Java ");
ausgeführt wird.
Zur Vereinfachung der Verarbeitung habe ich versucht, der Promise-ähnlichen Syntax von JavaScript näher zu kommen, außer dass ich am Ende ".start ()" aufgerufen habe, um die Promise-Kette auszulösen.
Wenn Sie den Lambda-Ausdruck nicht verwenden, lautet er wie folgt
Wenn ohne Verwendung des Lambda-Ausdrucks geschrieben
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();
Die Identität des Teils, in dem (Aktion, Daten) -> {}
die Schnittstelle ist, die die Funktion in JavaScript darstellt.
Func.java
public interface Func {
public void run(Action action, Object data) throws Exception;
}
Sie können "Promise.then (new Func ())" anstelle von "Promise.then (new Promise ())" verwenden. Wenn Sie "new Func" durch einen Lambda-Ausdruck ersetzen, wird es zu "Promise.then ((Aktion, Daten) -> {})", was es noch einfacher macht.
then(Func)Schreiben Sie mit
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) {
//Prozess 1 (Ausführung eines anderen Threads)
Func function1 = (action, data) -> {
new Thread(() -> {
System.out.println("Process-1");
Promise.sleep(1000);// Thread.Gleich wie Schlaf
action.resolve("Result-1");//Status"fulfilled"Und das Ergebnis im nächsten Prozess("Result-1")Sagen
}).start();//Starten Sie die asynchrone Verarbeitung in einem anderen Thread
};
//Prozess 2
Func function2 = (action, data) -> {
System.out.println("Process-2 result=" + data);
action.resolve();
};
Promise.resolve()//Starten Sie die Verarbeitung
.then(function1)//Ausführung von Prozess 1
.then(function2)//Ausführung von Prozess 2
.start();//Start
System.out.println("Hello,Promise");
}
** Ausführungsergebnis: **
Hello,Promise
Process-1
Process-2 result=Result-1
Erläuterung: Die Grammatik von ** dann ** lautet ** Promise.then (onFulfilled [, onRejected]); ** Das heißt, es können bis zu zwei Argumente verwendet werden. Das erste Argument ** onFulfilled ** wird ausgeführt, wenn die vorherige Ausführung mit dem Status erfüllt (≈successful) </ font> beendet wurde. Das zweite Argument ** onRejected ** ist optional, wird jedoch ausgeführt, wenn die vorherige Ausführung mit dem Status abgelehnt (≒ fehlgeschlagen) </ font> beendet wurde. Dieses Beispiel gibt nur das erste Argument an.
** Verarbeitungsablauf: **
Code:
public class Example21 {
public static void main(String[] args) {
Func function1 = (action, data) -> {
System.out.println("Process-1");
action.reject();//Status"rejected"Auf Ausführung setzen und abschließen
};
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, //Wird ausgeführt, wenn der Status erfüllt ist
function2_2 //Wird ausgeführt, wenn der Status abgelehnt wird
)
.start();
System.out.println("Hello,Promise");
}
}
** Ausführungsergebnis: **
Hello,Promise
Process-1
Rejected Process-2
Erläuterung:
** Funktion1 ** ist
action.reject();
Da dies abgeschlossen ist, wird der Status abgelehnt </ font>. Das nächste ** dann ** ist
.then(
function2_1, //Wird ausgeführt, wenn der Status erfüllt ist
function2_2 //Wird ausgeführt, wenn der Status abgelehnt wird
)
Es wird gesagt. Wie oben erwähnt, lautet die Syntax von ** dann ** ** Promise.then (onFulfilled [, onRejected]); **, also Da der Abschlussstatus von ** function1 ** abgelehnt wird </ font>, wird hier ** function2_2 ** ausgeführt, das zweite Argument von ** then **.
** Verarbeitungsablauf: **
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)//Der Status ist"fulfilled"Aber"rejected"Aber実行される
.start();
}
}
** Ausführungsergebnis: **
Received:I send REJECT
Erläuterung:
.always(function2)
** immer ((Aktion, Daten) -> {}) ** hat den Status <Schriftfarbe aufgrund abgelehnt, auch wenn der vorherige Prozess den Status erfüllt </ font> aufgrund aufgelöst hatte. Wird immer ausgeführt, unabhängig von = rot> abgelehnt </ font>.
** Verarbeitungsablauf: **
Code:
public class Example40 {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
//Asynchrone Verarbeitung 1
Func function1 = (action, data) -> {
new Thread(() -> {
Promise.sleep(1000); System.out.println("func1 running");action.resolve("func1-result");
}).start();
};
//Asynchrone Verarbeitung 2
Func function2 = (action, data) -> {
new Thread(() -> {
Promise.sleep(500);System.out.println("func2 running"); action.resolve("func2-result");
}).start();
};
//Asynchrone Verarbeitung 3
Func function3 = (action, data) -> {
new Thread(() -> {
Promise.sleep(100);System.out.println("func3 running");action.resolve("func3-result");
}).start();
};
//Der Prozess des endgültigen Empfangs des Ergebnisses
Func function4 = (action, data) -> {
System.out.println("Erhielt das Ergebnis");
List<Object> resultList = (List<Object>) data;
for (int i = 0; i < resultList.size(); i++) {
Object result = resultList.get(i);
System.out.println("Asynchrone Verarbeitung" + (i + 1) + "Das Ergebnis von" + result);
}
action.resolve();
};
Promise.all(function1, function2, function3)
.always(function4)
.start();
}
}
** Ausführungsergebnis: **
func3 running
func2 running
func1 running
Erhielt das Ergebnis der asynchronen Verarbeitung
Das Ergebnis des asynchronen Prozesses 1 ist func1-result
Das Ergebnis der asynchronen Verarbeitung 2 ist func2-result
Das Ergebnis der asynchronen Verarbeitung 3 ist func3-result
Erläuterung:
--Wenn die parallele Ausführung beendet ist, wechselt der Prozess zum verketteten ** dann ** (hier ** immer **).
Im obigen Beispiel werden ** Funktion1, Funktion2, Funktion3 ** parallel ausgeführt, aber wenn ** Funktion1 bis Funktion3 ** alle mit erfüllt </ font> abgeschlossen sind, wird jeder * Die Ergebnisse von * Funktion1 bis Funktion3 ** werden in ** Liste ** gespeichert und an ** dann ** übergeben. Zu diesem Zeitpunkt ist die Speicherreihenfolge die im Argument angegebene Reihenfolge von ** Funktion1, Funktion2, Funktion3 **. (Diese Spezifikation entspricht auch dem JavaScript-Versprechen.)
** Wenn eine der Funktionen1 bis Funktion3 ** fehlschlägt ≒ ablehnen </ font>, wird zuerst </ font> abgelehnt. Das Ergebnis (Ablehnungsgrund) der Funktion wird an das nächste ** dann ** übergeben. (Fail-Fast-Prinzip)
** Verarbeitungsablauf: **
Wie in (4) erläutert, kann ** Func ** parallel zu ** Promise.all ** betrieben werden, aber ** Executor ** wird als Thread-Erstellungsrichtlinie verwendet, wenn der Parallelbetrieb im Voraus ausgeführt wird. Kann definiert werden. Außerdem kann der Thread-Pool, der bereits für einen anderen Zweck vorbereitet wurde, auf ** Promise.all ** umgeleitet werden.
** Codebeispiel: **
public class Example41 {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
final ExecutorService myExecutor = Executors.newFixedThreadPool(2);
//Asynchrone Verarbeitung 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();
};
//Asynchrone Verarbeitung 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();
};
//Asynchrone Verarbeitung 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();
};
//Der Prozess des endgültigen Empfangs des Ergebnisses
Func function4 = (action, data) -> {
System.out.println("No.4 final " + Thread.currentThread());
System.out.println("Erhielt das Ergebnis");
List<Object> resultList = (List<Object>) data;
for (int i = 0; i < resultList.size(); i++) {
Object result = resultList.get(i);
System.out.println("Asynchrone Verarbeitung" + (i + 1) + "Das Ergebnis von" + result);
}
myExecutor.shutdown();
action.resolve();
};
Promise.all(myExecutor, function1, function2, function3)
.always(function4)
.start();
}
}
** Ausführungsergebnis: **
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]
Erhielt das Ergebnis
Das Ergebnis des asynchronen Prozesses 1 ist func1-result
Das Ergebnis der asynchronen Verarbeitung 2 ist func2-result
Das Ergebnis der asynchronen Verarbeitung 3 ist func3-result
Die Ergebnisse zeigen, dass ** Func ** auf Threads ausgeführt wird, die aus demselben Thread-Pool stammen. (Da die asynchrone Verarbeitung (neuer Thread) absichtlich in Func ausgeführt wird, befindet sich die asynchrone Verarbeitung außerhalb des angegebenen Thread-Pools.)
Erläuterung:
-Definieren Sie den ** Executor **, der zum Ausführen von ** Promise.all ** verwendet wird. Unten ist ein Thread-Pool mit einer Poolgröße von 2.
final ExecutorService myExecutor = Executors.newFixedThreadPool(2);
Promise.all(myExecutor, function1, function2, function3)
.always(function4)
.start();
Func function4 = (action, data) -> {
//Unterlassung
myExecutor.shutdown();
action.resolve();
};
** Threading-Richtlinie: **
Ich habe versucht, "Versprechen wie JavaScript" in Java zu schreiben
Wenn Sie den Java8-Lambda-Ausdruck gut verwenden, können Sie Promise in einer Form ausführen, die der JavaScript-Notation nahe kommt. ――Ich möchte aus der Entwicklung von JavaScript (ES) und anderen skriptbasierten Sprachen lernen, dass Sie mit einfacher Notation eine raffinierte Verarbeitung durchführen können. (Die asynchrone Ausführung hat sich auch in JavaScript zu ** async / await ** entwickelt.)
Der bibliothekseitige Quellcode von Promise (** Java-Versprechen **) in Java ist unten
https://github.com/riversun/java-promise
--git Klon https: // github.com / Riversun / Java-Versprechen.git
--mvn test
gibt Ihnen einen Unit-Test.
Darüber hinaus ist der in diesem Artikel veröffentlichte Beispielcode unten aufgeführt. https://github.com/riversun/java-promise-examples/tree/master-ja
Recommended Posts