This is a multi-threaded test code, each time a newSingleThreadExecutor is created, and two other threads are constantly triggering gc. Under HotSpot java8 (1.8.0_221), there will be an error that the thread pool has been closed.
public class ThreadPoolTest {
public static void main(String[] args) {
final ThreadPoolTest threadPoolTest = new ThreadPoolTest();
for (int i = 0; i < 8; i++) {
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
Future<String> future = threadPoolTest.submit();
try {
String s = future.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (Error e) {
e.printStackTrace();
}
}
}
}).start();
}
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
System.gc();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
System.gc();
}
}
}).start();
}
public Future<String> submit() {
ExecutorService executorService = Executors.newSingleThreadExecutor();
FutureTask<String> futureTask = new FutureTask(new Callable() {
@Override
public Object call() throws Exception {
Thread.sleep(50);
return System.currentTimeMillis() + "";
}
});
executorService.execute(futureTask);
return futureTask;
}
}
After running for a while, you will get an error:
Exception in thread "Thread-2" java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@a5acd19 rejected from java.util.concurrent.ThreadPoolExecutor@30890a38[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
at java.util.concurrent.Executors$DelegatedExecutorService.execute(Executors.java:668)
at ThreadPoolTest.submit(ThreadPoolTest.java:54)
at ThreadPoolTest$1.run(ThreadPoolTest.java:12)
at java.lang.Thread.run(Thread.java:748)
Executors.newSingleThreadExecutor creates an auto-closed thread pool (java.util.concurrent.Executors.FinalizableDelegatedExecutorService), so it should only be executed shutdown before the object is collect.
But from the error log, the executorService was shutdown in advance. Like before the stack frame popped, the finalized method of the executorService was executed ahead of time.
Why does this happen?