This is an automated email from the ASF dual-hosted git repository.
ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-lang.git
The following commit(s) were added to refs/heads/master by this push:
new 21b1c297d [LANG-1817] UncheckedFutureImpl clears thread interrupt
status when wrapping InterruptedException.
21b1c297d is described below
commit 21b1c297d4da30b4b973d92077244959387dafc7
Author: Gary Gregory <[email protected]>
AuthorDate: Sat Feb 7 15:01:43 2026 -0500
[LANG-1817] UncheckedFutureImpl clears thread interrupt status when
wrapping InterruptedException.
Sort members
---
.../lang3/concurrent/UncheckedFutureTest.java | 116 ++++++++++-----------
1 file changed, 57 insertions(+), 59 deletions(-)
diff --git
a/src/test/java/org/apache/commons/lang3/concurrent/UncheckedFutureTest.java
b/src/test/java/org/apache/commons/lang3/concurrent/UncheckedFutureTest.java
index db8f59fda..9d1bfdb02 100644
--- a/src/test/java/org/apache/commons/lang3/concurrent/UncheckedFutureTest.java
+++ b/src/test/java/org/apache/commons/lang3/concurrent/UncheckedFutureTest.java
@@ -78,6 +78,63 @@ public V get(final long timeout, final TimeUnit unit) throws
InterruptedExceptio
}
+ private static void assertInterruptPreserved(final
Consumer<UncheckedFuture<Integer>> call) throws Exception {
+ final CountDownLatch enteredGet = new CountDownLatch(1);
+ final Future<Integer> blockingFuture = new
AbstractFutureProxy<Integer>(ConcurrentUtils.constantFuture(42)) {
+
+ private final CountDownLatch neverRelease = new CountDownLatch(1);
+
+ @Override
+ public Integer get() throws InterruptedException {
+ enteredGet.countDown();
+ neverRelease.await();
+ throw new AssertionError("We should not get here");
+ }
+
+ @Override
+ public Integer get(final long timeout, final TimeUnit unit) throws
InterruptedException {
+ enteredGet.countDown();
+ neverRelease.await();
+ throw new AssertionError("We should not get here");
+ }
+
+ @Override
+ public boolean isDone() {
+ return false;
+ }
+ };
+ final UncheckedFuture<Integer> uf = UncheckedFuture.on(blockingFuture);
+ final AtomicReference<Throwable> thrown = new AtomicReference<>();
+ final AtomicBoolean interruptObserved = new AtomicBoolean(false);
+ final Thread worker = new Thread(() -> {
+ try {
+ call.accept(uf);
+ thrown.set(new AssertionError("We should not get here"));
+ } catch (final Throwable e) {
+ interruptObserved.set(Thread.currentThread().isInterrupted());
+ thrown.set(e);
+ }
+ }, "unchecked-future-test-worker");
+ worker.start();
+ assertTrue(enteredGet.await(2, TimeUnit.SECONDS), "Worker did not
enter Future.get() in time");
+ worker.interrupt();
+ worker.join();
+ final Throwable t = thrown.get();
+ assertInstanceOf(UncheckedInterruptedException.class, t, "Unexpected
exception: " + t);
+ assertInstanceOf(InterruptedException.class, t.getCause(), "Cause
should be InterruptedException");
+ assertTrue(interruptObserved.get(), "Interrupt flag was not restored
by the wrapper");
+ }
+
+ @Test
+ void interruptFlagIsPreservedOnGet() throws Exception {
+ assertInterruptPreserved(UncheckedFuture::get);
+ }
+
+ @Test
+ void interruptFlagIsPreservedOnGetWithTimeout() throws Exception {
+ assertInterruptPreserved(uf -> uf.get(1, TimeUnit.DAYS));
+ }
+
@Test
void testGetExecutionException() {
final ExecutionException e = new ExecutionException(new Exception());
@@ -126,63 +183,4 @@ void testOnCollection() {
void testOnFuture() {
assertEquals("Z", UncheckedFuture.on(new TestFuture<>("Z")).get());
}
-
-
- @Test
- void interruptFlagIsPreservedOnGet() throws Exception {
- assertInterruptPreserved(UncheckedFuture::get);
- }
-
- @Test
- void interruptFlagIsPreservedOnGetWithTimeout() throws Exception {
- assertInterruptPreserved(uf -> uf.get(1, TimeUnit.DAYS));
- }
-
- private static void
assertInterruptPreserved(Consumer<UncheckedFuture<Integer>> call) throws
Exception {
- final CountDownLatch enteredGet = new CountDownLatch(1);
- final Future<Integer> blockingFuture = new
AbstractFutureProxy<Integer>(ConcurrentUtils.constantFuture(42)) {
- private final CountDownLatch neverRelease = new CountDownLatch(1);
-
- @Override
- public Integer get() throws InterruptedException {
- enteredGet.countDown();
- neverRelease.await();
- throw new AssertionError("We should not get here");
- }
-
- @Override
- public Integer get(long timeout, TimeUnit unit) throws
InterruptedException {
- enteredGet.countDown();
- neverRelease.await();
- throw new AssertionError("We should not get here");
- }
-
- @Override
- public boolean isDone() {
- return false;
- }
-
- };
- final UncheckedFuture<Integer> uf = UncheckedFuture.on(blockingFuture);
- final AtomicReference<Throwable> thrown = new AtomicReference<>();
- final AtomicBoolean interruptObserved = new AtomicBoolean(false);
- final Thread worker = new Thread(() -> {
- try {
- call.accept(uf);
- thrown.set(new AssertionError("We should not get here"));
- } catch (Throwable e) {
- interruptObserved.set(Thread.currentThread().isInterrupted());
- thrown.set(e);
- }
- }, "unchecked-future-test-worker");
- worker.start();
- assertTrue(enteredGet.await(2, TimeUnit.SECONDS), "Worker did not
enter Future.get() in time");
- worker.interrupt();
- worker.join();
- final Throwable t = thrown.get();
- assertInstanceOf(UncheckedInterruptedException.class, t, "Unexpected
exception: " + t);
- assertInstanceOf(InterruptedException.class, t.getCause(), "Cause
should be InterruptedException");
- assertTrue(interruptObserved.get(), "Interrupt flag was not restored
by the wrapper");
- }
-
}