Skip to content

Commit af3f5d8

Browse files
author
Alan Bateman
committed
8347039: ThreadPerTaskExecutor terminates if cancelled tasks still running
Reviewed-by: vklang
1 parent 91197b3 commit af3f5d8

File tree

2 files changed

+64
-12
lines changed

2 files changed

+64
-12
lines changed

src/java.base/share/classes/java/util/concurrent/ThreadPerTaskExecutor.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -318,8 +318,12 @@ Thread thread() {
318318
}
319319

320320
@Override
321-
protected void done() {
322-
executor.taskComplete(thread);
321+
public void run() {
322+
try {
323+
super.run();
324+
} finally {
325+
executor.taskComplete(thread);
326+
}
323327
}
324328
}
325329

test/jdk/java/util/concurrent/ThreadPerTaskExecutor/ThreadPerTaskExecutorTest.java

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,7 @@
2323

2424
/*
2525
* @test id=platform
26+
* @bug 8284161 8347039
2627
* @summary Basic tests for new thread-per-task executors
2728
* @run junit/othervm -DthreadFactory=platform ThreadPerTaskExecutorTest
2829
*/
@@ -157,6 +158,7 @@ void testShutdown(ExecutorService executor) throws Exception {
157158
assertTrue(executor.isShutdown());
158159
assertFalse(executor.isTerminated());
159160
assertFalse(executor.awaitTermination(500, TimeUnit.MILLISECONDS));
161+
assertFalse(future.isDone());
160162
} finally {
161163
future.cancel(true); // interrupt task
162164
}
@@ -280,13 +282,13 @@ void testClose5(ExecutorService executor) throws Exception {
280282
}
281283

282284
/**
283-
* Test awaitTermination when not shutdown.
285+
* Test awaitTermination with no tasks running.
284286
*/
285287
@ParameterizedTest
286288
@MethodSource("executors")
287289
void testAwaitTermination1(ExecutorService executor) throws Exception {
288290
assertFalse(executor.awaitTermination(100, TimeUnit.MILLISECONDS));
289-
executor.close();
291+
executor.shutdown();
290292
assertTrue(executor.awaitTermination(100, TimeUnit.MILLISECONDS));
291293
}
292294

@@ -296,16 +298,62 @@ void testAwaitTermination1(ExecutorService executor) throws Exception {
296298
@ParameterizedTest
297299
@MethodSource("executors")
298300
void testAwaitTermination2(ExecutorService executor) throws Exception {
299-
Phaser barrier = new Phaser(2);
300-
Future<?> future = executor.submit(barrier::arriveAndAwaitAdvance);
301+
var started = new CountDownLatch(1);
302+
var stop = new CountDownLatch(1);
303+
Future<?> future = executor.submit(() -> {
304+
started.countDown();
305+
stop.await();
306+
return null;
307+
});
308+
started.await();
309+
try {
310+
executor.shutdown();
311+
assertFalse(executor.awaitTermination(1, TimeUnit.SECONDS));
312+
assertFalse(future.isDone());
313+
} finally {
314+
stop.countDown();
315+
}
316+
assertTrue(executor.awaitTermination(1, TimeUnit.MINUTES));
317+
assertTrue(future.isDone());
318+
}
319+
320+
/**
321+
* Test awaitTermination with cancelled task still running.
322+
*/
323+
@ParameterizedTest
324+
@MethodSource("executors")
325+
void testAwaitTermination3(ExecutorService executor) throws Exception {
326+
var started = new CountDownLatch(1);
327+
var stop = new CountDownLatch(1);
328+
Future<?> future = executor.submit(() -> {
329+
started.countDown();
330+
stop.await();
331+
return null;
332+
});
333+
started.await();
301334
try {
335+
future.cancel(false);
302336
executor.shutdown();
303-
assertFalse(executor.awaitTermination(100, TimeUnit.MILLISECONDS));
304-
barrier.arriveAndAwaitAdvance();
305-
assertTrue(executor.awaitTermination(10, TimeUnit.SECONDS));
337+
assertFalse(executor.awaitTermination(1, TimeUnit.SECONDS));
306338
} finally {
307-
future.cancel(true);
339+
stop.countDown();
308340
}
341+
assertTrue(executor.awaitTermination(1, TimeUnit.MINUTES));
342+
}
343+
344+
/**
345+
* Test awaitTermination with cancelled task that may not have started execution.
346+
*/
347+
@ParameterizedTest
348+
@MethodSource("executors")
349+
void testAwaitTermination4(ExecutorService executor) throws Exception {
350+
Future<?> future = executor.submit(() -> {
351+
Thread.sleep(Duration.ofMillis(50));
352+
return null;
353+
});
354+
future.cancel(false);
355+
executor.shutdown();
356+
assertTrue(executor.awaitTermination(1, TimeUnit.MINUTES));
309357
}
310358

311359
/**

0 commit comments

Comments
 (0)