这是MCVE:
public static void main(String[] args) {
CompletableFuture<String> r1 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return "41";
});
CompletableFuture<String> r2 = CompletableFuture.supplyAsync(() -> "42");
CompletableFuture<String> r3 = CompletableFuture.supplyAsync(() -> {
System.out.println("I'm called.");
return "43";
});
CompletableFuture.allOf(r1, r2, r3).thenRun(() -> { System.out.println("End."); });
Stream.of(r1, r2, r3).forEach(System.out::println);
}
Run Code Online (Sandbox Code Playgroud)
有点好奇,没有实际完成CompletableFuture从allOf(...),例如调用它join(),我得到以下输出:
I'm called.
java.util.concurrent.CompletableFuture@<...>[Not completed, 1 dependents]
java.util.concurrent.CompletableFuture@<...>[Completed normally]
java.util.concurrent.CompletableFuture@<...>[Completed normally]
Run Code Online (Sandbox Code Playgroud)
我可以知道是什么导致JVM处理/认为r1有1(估计数量)依赖CompletableFuture …
第一个回调电话很快,其余的延迟~50ms(非加法),我不知道为什么.
public class CfTest {
final static long t0 = System.nanoTime();
public static void main(String[] args) {
CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(()->{sleep(2000); return 100;});
CompletableFuture<Long> cf2 = CompletableFuture.supplyAsync(()->{sleep(1000); return 1L;});
CompletableFuture<Long> cfs = cf1.thenCombine(cf2, (a,b)->a+b);
cfs.thenAccept(x->debug("a1. " + x)); // Async process, sync when complete
cfs.thenAccept(x->debug("a2. " + x)); // Async process, sync when complete
cfs.thenAcceptAsync(x->debug("a3. " + x)); // Async process, async after complete too
debug("b. " + cfs.join()); // Wait and process
debug("c. " + cfs.join()); // Wait and …Run Code Online (Sandbox Code Playgroud) 我试图掌握Java 8 CompletableFuture.我怎样才能将这些人加入到"allOf"之后再归还给他们.下面的代码不起作用,但让你知道我尝试过的.
在javascript ES6中我会这样做
Promise.all([p1, p2]).then(function(persons) {
console.log(persons[0]); // p1 return value
console.log(persons[1]); // p2 return value
});
Run Code Online (Sandbox Code Playgroud)
到目前为止我在Java方面的努力
public class Person {
private final String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
@Test
public void combinePersons() throws ExecutionException, InterruptedException {
CompletableFuture<Person> p1 = CompletableFuture.supplyAsync(() -> {
return new Person("p1");
});
CompletableFuture<Person> p2 = CompletableFuture.supplyAsync(() -> {
return new Person("p1");
});
CompletableFuture.allOf(p1, p2).thenAccept(it -> System.out.println(it));
}
Run Code Online (Sandbox Code Playgroud) 所以我有一个方法返回一个CompletableFuture.在返回之前,此方法添加一个块,thenAccept在CompletableFuture完成后执行该块.
此方法的调用者还添加了另一个块thenAccept.显然,这可以继续多个链式调用.
调用CompletionStage返回的顺序是什么thenAccept?是否保证是添加它们的顺序?如果没有,如何保证它们按照添加顺序执行?
PS:我根据自己的经验CompletableFuture和本文提出这个问题
回答这个问题的时候,我注意到了一个奇怪的行为CompletableFuture:如果你有一个CompletableFuture cf和一个调用链cf.exceptionally(),调用cf.get()似乎表现得很奇怪:
exceptionally()在返回之前等待块的执行ExecutionException我错过了什么或这是一个错误吗?我在Ubuntu 17.04上使用Oracle JDK 1.8.0_131.
以下代码说明了这种现象:
public static void main(String[] args) {
long start = System.currentTimeMillis();
final CompletableFuture<Object> future = CompletableFuture.supplyAsync(() -> {
sleep(1000);
throw new RuntimeException("First");
}).thenApply(Function.identity());
future.exceptionally(e -> {
sleep(1000);
logDuration(start, "Exceptionally");
return null;
});
final CompletableFuture<Void> futureA = CompletableFuture.runAsync(() -> {
try {
future.get();
} catch (Exception e) {
} finally {
logDuration(start, "A");
}
});
final CompletableFuture<Void> futureB = CompletableFuture.runAsync(() …Run Code Online (Sandbox Code Playgroud) CompletableFuture我想模拟当 a成功完成时正在调用一些代码。
我有这门课:
public class MyClassImplementRunner implements Runnable {
private final String param1;
public MyClassImplementRunner(String param1) {
this.param1 = param1;
}
public static CompletableFuture<Void> startAsync(String param1) {
return CompletableFuture.runAsync(
new MyClassImplementRunner(param1)).whenComplete(
(response, throwable) -> {
//some code when complete
});
@Override
public void run () {
//the runnable code
}
}
}
Run Code Online (Sandbox Code Playgroud)
在我的 Junit 中(使用 Mockito 和 Java 8),我需要模拟它
//some code when complete
Run Code Online (Sandbox Code Playgroud)
当 Future 成功完成时调用。
您能否提供一些关于如何实现这一目标的指示?
CompletableFuture 允许为异步调用提供回调。您可以创建一长串回调,其中每个异步调用将在完成时触发下一个回调。这被认为是编写异步代码的更好方法,而不是使用 Future,在 Future 中,您必须阻塞线程才能在触发下一个计算之前获取第一个计算的结果。
我可以理解 Completable Futures 中的回调链可以提供更具可读性的代码的论点,但我想知道这种方法是否也有性能优势,或者它只是一个语法糖?
例如,考虑以下代码:
ExecutorService exec = Executors.newSingleThreadExecutor();
CompletableFuture.supplyAsync(this::findAccountNumber, exec)
.thenApply(this::calculateBalance)
.thenApply(this::notifyBalance)
.thenAccept((i)->notifyByEmail())
.join();
Run Code Online (Sandbox Code Playgroud)
在此代码中,在完成calculateBalance()之前无法启动findAccountNumber(),因此回调链中的下一个方法基本上calculateBalance()被阻塞,依此类推。findAccountNumber()它比以下内容如何更好(性能方面):
ExecutorService exec = Executors.newSingleThreadExecutor();
Future<Integer> accountNumberFuture = exec.submit(findAccountNumberCallable);
Integer accountNumber = accountNumberFuture.get();
Future<String> calculateBalanceFuture = exec.submit(calculateBalanceCallable(accountNumber);
....
....
Run Code Online (Sandbox Code Playgroud) 我正在从我的 Spring Boot 应用程序调用不同的其他 Web 服务。为了提高性能而不是顺序调用它们,我想实现CompletableFuture.supplyAsync()异步执行。
我正在调用的服务,其中一些是内部的,一些是外部的。因此,对于内部,我直接调用它们的 api 接口,这些接口存在于 Maven 依赖项中,而对于外部接口,我正在使用javax.ws.rs.client.WebTarget
在实现调用时,CompletableFuture.supplyAsync()内部的客户端类会成功执行,而具有依赖关系的客户端类则会WebTarget因未创建 bean 而@Inject失败。scopedTarget.XXService_nameXX_wt
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.charityserv_wt': Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.ws.rs.client.WebTarget]: Factory method 'target' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.coreContext': Scope 'request' is not active for the current thread
Run Code Online (Sandbox Code Playgroud)
调用代码:
CompletableFuture<SearchResult> future = CompletableFuture.supplyAsync(() -> searchServiceClientImpl.getsearchSearchRequest(encryptedAccountNumber));
Run Code Online (Sandbox Code Playgroud)
服务客户端类:
@Component
public class …Run Code Online (Sandbox Code Playgroud) 我是 Junit 新手,最近遇到了这个问题。无论我在代码中使用 CompletableFuture,我都无法编写测试用例。就像下面的Java文件一样
更新
审计服务.java
@Autowired
Executor existingThreadPool;
@Override
public void auditData(List<ErrorDetails> alertList) {
CompletableFuture.runAsync(() -> {
if (alertList.isEmpty())
//privateMethodCall1
else
//privateMethodCall2
}, existingThreadPool);
}
Run Code Online (Sandbox Code Playgroud)
我点击此链接并尝试了下面的解决方案,但仍然出现 NPE for CompletableFuture 类似下面的错误。
审计服务测试.java
@InjectMock
AuditService auditService;
@Mock
private CompletableFuture<Void> completableFuture = null;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
completableFuture = CompletableFuture.runAsync(new Runnable() {
@Override
public void run() {}
},Executors.newSingleThreadExecutor());
}
@Test
public void shouldAuditData() {
List<ErrorDetails> alertList = new ArrayList();
auditService.auditData(alertList);
}
Run Code Online (Sandbox Code Playgroud)
错误
java.lang.NullPointerException
at java.util.concurrent.CompletableFuture.screenExecutor(CompletableFuture.java:415)
at java.util.concurrent.CompletableFuture.runAsync(CompletableFuture.java:1858)
at …Run Code Online (Sandbox Code Playgroud) 我的代码在 Java 8 中运行良好,但是当我将其迁移到 Java 17 时,它就不起作用了。它涉及 ThreadLocal 和 CompletableFuture.runAsync。
以下是课程:
public class UriParameterHandler {
}
public class DateRangeEntity {
public String getCurrentDate(){
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
LocalDateTime now = LocalDateTime.now();
return dtf.format(now);
}
}
public class SessionHandler {
private static ThreadLocal<SessionHandler> instance = new InheritableThreadLocal<>();
private UriParameterHandler uriParameterHandler;
private DateRangeEntity dateRangeEntity;
private SessionHandler() {
instance.set(this);
}
public static void initialize() {
SessionHandler handler = new SessionHandler();
handler.uriParameterHandler = new UriParameterHandler();
}
public static UriParameterHandler getUriParameterHandler() {
return instance.get().uriParameterHandler; …Run Code Online (Sandbox Code Playgroud) java ×10
java-8 ×4
mockito ×2
spring-boot ×2
asynchronous ×1
future ×1
java-17 ×1
jax-rs ×1
junit ×1
spring ×1
thread-local ×1