Skip to content

Commit f7c17c2

Browse files
committed
Fix Listener exec when it's added to the ListenableFuture after completion, close AsyncHttpClient#1128
1 parent becc8b7 commit f7c17c2

File tree

2 files changed

+37
-6
lines changed

2 files changed

+37
-6
lines changed

client/src/main/java/org/asynchttpclient/future/AbstractListenableFuture.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ public abstract class AbstractListenableFuture<V> implements ListenableFuture<V>
4545

4646
// The execution list to hold our executors.
4747
// lazy fields
48+
private volatile boolean hasRun;
4849
private volatile boolean executionListInitialized;
4950
private ExecutionList executionList;
5051

@@ -62,19 +63,20 @@ private ExecutionList executionList() {
6263
return executionListInitialized ? executionList : lazyExecutionList();
6364
}
6465

65-
/*
66-
* Adds a listener/executor pair to execution list to execute when this task is completed.
67-
*/
68-
66+
@Override
6967
public ListenableFuture<V> addListener(Runnable listener, Executor exec) {
7068
executionList().add(listener, exec);
69+
if (hasRun) {
70+
runListeners();
71+
}
7172
return this;
7273
}
7374

74-
/*
75+
/**
7576
* Execute the execution list.
7677
*/
7778
protected void runListeners() {
79+
hasRun = true;
7880
if (executionListInitialized) {
7981
executionList().run();
8082
}

client/src/test/java/org/asynchttpclient/ListenableFutureTest.java

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
*/
1313
package org.asynchttpclient;
1414

15-
import static org.asynchttpclient.Dsl.*;
15+
import static org.asynchttpclient.Dsl.asyncHttpClient;
1616
import static org.testng.Assert.assertEquals;
1717

1818
import java.util.concurrent.CountDownLatch;
@@ -49,4 +49,33 @@ public void run() {
4949
assertEquals(statusCode.get(), 200);
5050
}
5151
}
52+
53+
@Test(groups = "standalone")
54+
public void testListenableFutureAfterCompletion() throws Exception {
55+
56+
AtomicInteger counter = new AtomicInteger(1);
57+
58+
try (AsyncHttpClient ahc = asyncHttpClient()) {
59+
final ListenableFuture<Response> future = ahc.prepareGet(getTargetUrl()).execute();
60+
future.get();
61+
future.addListener(() -> counter.decrementAndGet(), Runnable::run);
62+
}
63+
assertEquals(0, counter.get());
64+
}
65+
66+
@Test(groups = "standalone")
67+
public void testListenableFutureBeforeAndAfterCompletion() throws Exception {
68+
69+
AtomicInteger counter = new AtomicInteger(2);
70+
71+
try (AsyncHttpClient ahc = asyncHttpClient()) {
72+
final ListenableFuture<Response> future = ahc.prepareGet(getTargetUrl()).execute();
73+
74+
future.addListener(() -> counter.decrementAndGet(), Runnable::run);
75+
76+
future.get();
77+
future.addListener(() -> counter.decrementAndGet(), Runnable::run);
78+
}
79+
assertEquals(0, counter.get());
80+
}
5281
}

0 commit comments

Comments
 (0)