并发 - 如何在J中异步调用方法
我最近一直在看Go的goroutines,并认为在Java中有类似的东西会很好。 据我所知,并行化方法调用的常用方法是执行以下操作:
final String x = "somethingelse";
new Thread(new Runnable() {
public void run() {
x.matches("something");
}
}).start();
那不是很优雅。 有没有更好的方法呢? 我在项目中需要这样的解决方案,所以我决定围绕异步方法调用实现自己的包装类。
我在J-Go发布了我的包装类。 但我不知道这是不是一个好的解决方案。 用法很简单:
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的类并执行一些Reflection工作来获取正确的方法对象并调用它。
我想对我的小型库以及在Java中进行这样的异步方法调用的主题有所了解。 安全吗? 有没有更简单的方法?
我刚刚发现有一种更清洁的方法可以做到
new Thread(new Runnable() {
public void run() {
//Do whatever
}
}).start();
(至少在Java 8中),您可以使用lambda表达式将其缩短为:
new Thread(() -> {
//Do whatever
}).start();
就像在JS中创建一个函数一样简单!
您可能还希望考虑课程FutureTask
。
如果您使用的是Java 5或更高版本,则FutureTask是&#34;可取消异步计算的交钥匙实现。&#34;
FutureTask
包中提供了更丰富的异步执行调度行为(例如,ScheduledExecutorService
),但FutureTask
可能具有您需要的所有功能。
我甚至会说,自从FutureTask
可用以来,不再使用您提供的第一个代码模式作为示例。 (假设您使用的是Java 5或更高版本。)
我不喜欢使用Reflection的想法。
不仅在某些重构中丢失它是危险的,但它也可以被FutureTask
拒绝。
FutureTask
是一个很好的选项,作为java.util.concurrent包中的其他选项。
我最喜欢的简单任务:
Executors.newSingleThreadExecutor().submit(task);
比创建一个Thread稍微短一点(task是Callable或Runnable)
Java 8在java.util.concurrent.CompletableFuture包中引入了CompletableFuture,可用于进行异步调用:
CompletableFuture.runAsync(() -> {
// method call or code to be asynch.
});
您可以使用来自jcabi-aspects和AspectJ的save()
注释:
public class Foo {
@Async
public void save() {
// to be executed in the background
}
}
当您致电save()
时,新线程将启动并执行其正文。 你的主线程继续而不等待save()
的结果。
您可以使用CompletableFuture的Java8语法,这样您就可以根据调用异步函数的结果执行其他异步计算。
例如:
CompletableFuture.supplyAsync(this::findSomeData)
.thenApply(this:: intReturningMethod)
.thenAccept(this::notify);
可以在本文中找到更多详细信息
您可以使用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/]
这并不是真正相关,但如果我要异步调用一个方法,例如 matches(),我会用:
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();
}
我测试了这个并且它有效。 只是认为如果他们只是来参加&#34;异步方法&#34;它可能会有所帮助。
它可能不是一个真正的解决方案,但现在 - 在Java 8中 - 您可以使用lambda表达式使这些代码看起来至少更好一些。
final String x = "somethingelse";
new Thread(() -> {
x.matches("something");
}
).start();
你甚至可以在一行中做到这一点,仍然具有可读性。
new Thread(() -> x.matches("something")).start();
你可以使用Cactoos的get()
:
boolean matches = new AsyncFunc(
x -> x.matches("something")
).apply("The text").get();
它将在后台执行,结果将在get()
中以Future
的形式提供。
Java还提供了一种调用异步方法的好方法。 在java.util.concurrent中,我们有ExecutorService,它有助于做同样的事情。 像这样初始化你的对象 -
private ExecutorService asyncExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
然后调用函数 -
asyncExecutor.execute(() -> {
TimeUnit.SECONDS.sleep(3L);}