Cómo llamar asincrónicamente un método en Java

Estuve mirando últimamente los goroutines de Go y pensé que sería bueno tener algo similar en Java. Por lo que he buscado, la forma más común de paralelizar una llamada a un método es hacer algo como:

final String x = "somethingelse"; new Thread(new Runnable() { public void run() { x.matches("something"); } }).start(); 

Eso no es muy elegante. ¿Hay una mejor manera de hacer esto? Necesitaba una solución de este tipo en un proyecto, así que decidí implementar mi propia clase contenedora en torno a una llamada a método asíncrono.

Publiqué mi clase contenedora en J-Go . Pero no sé si es una buena solución. El uso es simple:

 SampleClass obj = ... FutureResult 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 

o menos detallado:

 Go.with(obj).callLater("myRandomMethod"); //... Go away if (Go.lastResult().isReady()) //Blocks until myRandomMethod has ended System.out.println("Method is finished!"); 

Internamente estoy usando una clase que implementa Runnable y hago algunos trabajos de reflexión para obtener el objeto de método correcto e invocarlo.

Quiero una opinión sobre mi pequeña biblioteca y sobre el tema de hacer llamadas a métodos asíncronos como esta en Java. ¿Es seguro? ¿Ya hay una manera más simple?

Acabo de descubrir que hay una manera más limpia de hacer su

 new Thread(new Runnable() { public void run() { //Do whatever } }).start(); 

(Al menos en Java 8), puede usar una expresión lambda para acortarlo a:

 new Thread(() -> { //Do whatever }).start(); 

¡Tan simple como hacer una función en JS!

También puede considerar la clase java.util.concurrent.FutureTask .

Si está utilizando Java 5 o posterior, FutureTask es una implementación llave en mano de “Un cálculo asincrónico cancelable “.

Hay comportamientos de progtwigción de ejecución asíncrona aún más ricos disponibles en el paquete java.util.concurrent (por ejemplo, ScheduledExecutorService ), pero FutureTask puede tener toda la funcionalidad que necesita.

Incluso llegaría a decir que ya no es aconsejable utilizar el primer patrón de código que dio como ejemplo desde que FutureTask estuvo disponible. (Suponiendo que está en Java 5 o posterior)

No me gusta la idea de usar Reflection para eso.
No solo es peligroso por perderlo en algunas refactorizaciones, sino que SecurityManager también puede negarlo.

FutureTask es una buena opción como las otras opciones del paquete java.util.concurrent.
Mi favorito para tareas simples:

  Executors.newSingleThreadExecutor().submit(task); 

un poco más corto que la creación de un subproceso (la tarea es invocable o ejecutable)

Puede usar la anotación @Async de jcabi-aspects y AspectJ:

 public class Foo { @Async public void save() { // to be executed in the background } } 

Cuando llamas a save() , se inicia un nuevo hilo y ejecuta su cuerpo. Su hilo principal continúa sin esperar el resultado de save() .

Puede utilizar la syntax de Java8 para CompletableFuture, de esta manera puede realizar cálculos asíncronos adicionales basados ​​en el resultado de llamar a una función asíncrona.

por ejemplo:

  CompletableFuture.supplyAsync(this::findSomeData) .thenApply(this:: intReturningMethod) .thenAccept(this::notify); 

Más detalles se pueden encontrar en este artículo

Puede usar Future-AsyncResult para esto.

 @Async public Future 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(results); } 

Referencia: https://spring.io/guides/gs/async-method/

Java 8 introdujo CompletableFuture disponible en el paquete java.util.concurrent.CompletableFuture, se puede usar para realizar una llamada de asincronización:

 CompletableFuture.runAsync(() -> { // method call or code to be asynch. }); 

Esto no está realmente relacionado, pero si tuviera que llamar asincrónicamente a un método, por ejemplo, matches (), usaría:

 private final static ExecutorService service = Executors.newFixedThreadPool(10); public static Future matches(final String x, final String y) { return service.submit(new Callable() { @Override public Boolean call() throws Exception { return x.matches(y); } }); } 

Luego para llamar al método asincrónico que usaría:

 String x = "somethingelse"; try { System.out.println("Matches: "+matches(x, "something").get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } 

Lo he probado y funciona. Solo pensé que podría ayudar a otros si vinieran por el “método asincrónico”.

Probablemente no sea una solución real, pero ahora, en Java 8, puede hacer que este código se vea al menos un poco mejor utilizando la expresión lambda.

 final String x = "somethingelse"; new Thread(() -> { x.matches("something"); } ).start(); 

Y usted podría incluso hacer esto en una línea, todavía teniendo bastante legible.

 new Thread(() -> x.matches("something")).start(); 

Puedes usar AsyncFunc de Cactoos :

 boolean matches = new AsyncFunc( x -> x.matches("something") ).apply("The text").get(); 

Se ejecutará en segundo plano y el resultado estará disponible en get() como Future .