如何在 Java 中异步调用方法

我最近一直在研究 高舞动作,觉得在 Java 中使用类似的代码会很不错。就我所知,并行化方法调用的常用方法是这样做的:

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

这可不怎么优雅。我在一个项目中需要这样的解决方案,所以我决定围绕一个异步方法调用实现我自己的包装类。

我在 走吧中发布了我的包装类。但我不知道这是不是个好办法。用法很简单:

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

或者不那么冗长:

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

在内部,我使用一个实现 Runnable 的类,并执行一些反射工作来获得正确的方法对象并调用它。

我想了解一些关于我的小型库以及在 Java 中进行这样的异步方法调用的主题的意见。安全吗?已经有更简单的方法了吗?

392058 次浏览

您可能还希望考虑 java.util.concurrent.FutureTask类。

如果您正在使用 Java5或更高版本,未来任务是“可取消的异步计算”的交钥匙实现

java.util.concurrent包(例如,ScheduledExecutorService)中甚至有更丰富的异步执行调度行为,但是 FutureTask可能具有您需要的所有功能。

我甚至可以说,自从 FutureTask可用以来,不再建议使用您提供的第一个代码模式作为示例。(假设您使用的是 Java5或更高版本。)

我不喜欢使用反射的想法。
在某些重构中错过它不仅是危险的,而且 SecurityManager也可以拒绝它。

FutureTask是一个很好的选项,它是 java.util.concurlpackage 中的其他选项。
我最喜欢的简单任务是:

    Executors.newSingleThreadExecutor().submit(task);

比创建 Thread 短一点(任务是 Callable 或 Runnable)

您可以使用来自 Jcabi 方面和 AspectJ 的 @Async注释:

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

当您调用 save()时,一个新线程启动并执行它的主体。您的主线程继续运行,而不需要等待 save()的结果。

我刚发现有一个更干净的方法

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

(至少在 Java8中) ,可以使用 lambda 表达式将其缩短为:

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

就像在 JS 中创建函数一样简单!

这并不是真正相关的,但是如果我要异步调用一个方法,例如 match () ,我会使用:

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);
}


});
}

然后调用异步方法,我将使用:

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

我已经测试过了,很有效。只是觉得如果他们只是为了“异步方法”而来,也许会对其他人有所帮助。

可以为此使用 Future-AsyncResult。

@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);
}

参考资料: https://spring.io/guides/gs/async-method/

这可能不是一个真正的解决方案,但是现在-在 Java8中-您可以使用 lambda 表达式使这段代码看起来至少好一点。

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

你甚至可以用一行代码来完成这个操作,而且仍然保持可读性。

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

你可以从 仙人掌使用 AsyncFunc:

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

它将在后台执行,结果将在 get()中作为 Future提供。

您可以使用 CompletableFuture 的 Java8语法,这样就可以根据调用异步函数的结果执行额外的异步计算。

例如:

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

更多细节可以在这个 文章中找到

Java 8引入了 CompletableFuture,可以在 Java.util.concurt.CompletableFuture 包中使用,可以用来进行异步调用:

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

Java 还提供了一种调用异步方法的好方法。在 并发中,我们有 执行服务来帮助我们做同样的事情。像这样初始化对象-

 private ExecutorService asyncExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

然后调用类似-的函数

asyncExecutor.execute(() -> {


TimeUnit.SECONDS.sleep(3L);}

还有一个由 EA: https://github.com/electronicarts/ea-async创建的 Async-Await 图书馆

摘自他们的自述:

和电子艺界异步合作

import static com.ea.async.Async.await;
import static java.util.concurrent.CompletableFuture.completedFuture;


public class Store
{
public CompletableFuture<Boolean> buyItem(String itemTypeId, int cost)
{
if(!await(bank.decrement(cost))) {
return completedFuture(false);
}
await(inventory.giveItem(itemTypeId));
return completedFuture(true);
}
}

没有电子艺界异步

import static java.util.concurrent.CompletableFuture.completedFuture;


public class Store
{
public CompletableFuture<Boolean> buyItem(String itemTypeId, int cost)
{
return bank.decrement(cost)
.thenCompose(result -> {
if(!result) {
return completedFuture(false);
}
return inventory.giveItem(itemTypeId).thenApply(res -> true);
});
}
}