Почему локальные переменные в методе заранее собираются мусором?
Это многопоточный тестовый код, каждый раз, когда создается newSingleThreadExecutor, а два других потока постоянно запускают gc. В HotSpot java8 (1.8.0_221) будет ошибка, что пул потоков был закрыт.
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;
}
}
Через некоторое время вы получите сообщение об ошибке:
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 создает автоматически закрывающийся пул потоков (java.util.concurrent.Executors.FinalizableDelegatedExecutorService), поэтому его следует выполнять только после завершения работы перед сбором объекта.
Но, судя по журналу ошибок, execorService был отключен заранее. Как и до того, как фрейм стека выскочил, финализированный метод executeorService был выполнен заранее.
Почему это происходит?