Je suis en train de regarder les goroutines de Go récemment et j'ai pensé qu'il serait agréable d'avoir quelque chose de similaire en Java. Dans la mesure où j'ai recherché la méthode la plus courante pour paralléliser un appel de méthode, procédez comme suit:
final String x = "somethingelse";
new Thread(new Runnable() {
public void run() {
x.matches("something");
}
}).start();
Ce n'est pas très élégant. Y a-t-il un meilleur moyen de faire cela? Comme j'avais besoin d'une telle solution dans un projet, j'ai donc décidé d'implémenter ma propre classe de wrapper autour d'un appel de méthode asynchrone.
J'ai publié ma classe wrapper dans J-Go . Mais je ne sais pas si c'est une bonne solution. L'utilisation est simple:
SampleClass obj = ...
FutureResult<Integer> res = ...
Go go = new Go(obj);
go.callLater(res, "intReturningMethod", 10); //10 is a Integer method parameter
//... Do something else
//...
System.out.println("Result: "+res.get()); //Blocks until intReturningMethod returns
ou moins verbeux:
Go.with(obj).callLater("myRandomMethod");
//... Go away
if (Go.lastResult().isReady()) //Blocks until myRandomMethod has ended
System.out.println("Method is finished!");
En interne, j'utilise une classe qui implémente Runnable et effectue des travaux de réflexion pour obtenir le bon objet de méthode et l'appeler.
Je veux des opinions sur ma minuscule bibliothèque et sur le fait de faire des appels de méthodes asynchrones comme celui-ci en Java. Est-ce sûr? Y a-t-il déjà un moyen plus simple?
Je viens de découvrir qu’il existe un moyen plus propre de faire votre
new Thread(new Runnable() {
public void run() {
//Do whatever
}
}).start();
(Au moins dans Java 8), vous pouvez utiliser une expression lambda pour la raccourcir afin de:
new Thread(() -> {
//Do whatever
}).start();
Aussi simple que de créer une fonction dans JS!
Java 8 introduit CompletableFuture disponible dans le package Java.util.concurrent.CompletableFuture, peut être utilisé pour effectuer un appel asynchrone:
CompletableFuture.runAsync(() -> {
// method call or code to be asynch.
});
Vous voudrez peut-être aussi considérer la classe Java.util.concurrent.FutureTask
.
Si vous utilisez Java 5 ou une version ultérieure, FutureTask est une implémentation clé en main de "Un calcul asynchrone annulable."
Il existe même des comportements de planification d'exécution asynchrone plus riches disponibles dans le package Java.util.concurrent
(Par exemple, ScheduledExecutorService
), mais FutureTask
peut disposer de toutes les fonctionnalités dont vous avez besoin.
J'irais même jusqu'à dire qu'il n'est plus conseillé d'utiliser le premier modèle de code que vous avez donné comme exemple depuis que FutureTask
est devenu disponible. (En supposant que vous êtes sur Java 5 ou une version ultérieure.)
je n'aime pas l'idée d'utiliser Reflection pour cela.
Non seulement dangereux de ne pas l'avoir dans certaines refactorisations, il peut aussi être refusé par SecurityManager
.
FutureTask
est une bonne option comme les autres options du paquet Java.util.concurrent.
Mon préféré pour les tâches simples:
Executors.newSingleThreadExecutor().submit(task);
pe peu plus long que la création d'un thread (la tâche est un appelable ou un exécutable)
Vous pouvez utiliser la syntaxe Java8 pour CompletableFuture afin d'effectuer d'autres calculs asynchrones en fonction du résultat de l'appel d'une fonction asynchrone.
par exemple:
CompletableFuture.supplyAsync(this::findSomeData)
.thenApply(this:: intReturningMethod)
.thenAccept(this::notify);
Plus de détails peuvent être trouvés dans ceci article
Vous pouvez utiliser @Async
l'annotation de jcabi-aspects et AspectJ:
public class Foo {
@Async
public void save() {
// to be executed in the background
}
}
Lorsque vous appelez save()
, un nouveau thread démarre et exécute son corps. Votre thread principal continue sans attendre le résultat de save()
.
Vous pouvez utiliser Future-AsyncResult pour cela.
@Async
public Future<Page> findPage(String page) throws InterruptedException {
System.out.println("Looking up " + page);
Page results = restTemplate.getForObject("http://graph.facebook.com/" + page, Page.class);
Thread.sleep(1000L);
return new AsyncResult<Page>(results);
}
Référence: https://spring.io/guides/gs/async-method/
Ce n'est probablement pas une vraie solution, mais maintenant - dans Java 8 - Vous pouvez faire en sorte que ce code paraisse au moins un peu meilleur en utilisant l'expression lambda.
final String x = "somethingelse";
new Thread(() -> {
x.matches("something");
}
).start();
Et vous pouvez même le faire en une ligne, tout en restant assez lisible.
new Thread(() -> x.matches("something")).start();
Java fournit également un moyen simple d'appeler des méthodes asynchrones. dans Java.util.concurrent nous avons ExecutorService qui nous aide à faire de même. Initialisez votre objet comme ceci -
private ExecutorService asyncExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
puis appelez la fonction like-
asyncExecutor.execute(() -> {
TimeUnit.SECONDS.sleep(3L);}
Ce n’est pas vraiment lié, mais si j’appelais de manière asynchrone une méthode, par exemple. allumettes (), je voudrais utiliser:
private final static ExecutorService service = Executors.newFixedThreadPool(10);
public static Future<Boolean> matches(final String x, final String y) {
return service.submit(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
return x.matches(y);
}
});
}
Ensuite, pour appeler la méthode asynchrone, je voudrais utiliser:
String x = "somethingelse";
try {
System.out.println("Matches: "+matches(x, "something").get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
J'ai testé cela et ça marche. J'ai pensé que cela pourrait aider les autres s'ils venaient pour la "méthode asynchrone".