Eug*_*ene 4 java executorservice java-8
在我们的一项服务中,有人添加了这样的代码(简化):
public class DeleteMe {
public static void main(String[] args) {
DeleteMe d = new DeleteMe();
for (int i = 0; i < 10_000; ++i) {
d.trigger(i);
}
}
private Future<?> trigger(int i) {
ExecutorService es = Executors.newSingleThreadExecutor();
Future<?> f = es.submit(() -> {
try {
// some long running task
Thread.sleep(10_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
return f;
}
}
Run Code Online (Sandbox Code Playgroud)
有时由于以下原因而失败:
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@3148f668 rejected from java.util.concurrent.ThreadPoolExecutor@6e005dc9[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.AbstractExecutorService.submit(AbstractExecutorService.java:112)
at java.util.concurrent.Executors$DelegatedExecutorService.submit(Executors.java:678)
at com.erabii.so.DeleteMe.trigger(DeleteMe.java:29)
at com.erabii.so.DeleteMe.main(DeleteMe.java:22)
Run Code Online (Sandbox Code Playgroud)
在大多数情况下,错误是OutOfMemoryError-我完全理解。编写该代码的人从未调用过ExecutorService::shutDown,因此使它保持了太多的生命。当然,为每个方法调用创建单独的执行服务都是很糟糕的,并且会被更改;但这正是为什么看到错误的原因。
我不明白的是为什么RejectedExecutionException会被抛出,特别是在这里被抛出。
- 如果我们无法将任务排队,则尝试添加一个新线程。如果失败,我们知道我们已关闭或已饱和,因此拒绝该任务。
如果确实如此,为什么文档execute中没有提及?
如果由于执行程序已关闭或已达到其能力而无法提交任务执行,则该任务由当前的RejectedExecutionHandler处理。
坦率地说,虽然我ExecutorService是由GC编写的-可访问性和范围是不同的东西,并且允许GC清除所有无法访问的内容;但是有一个Future<?>可以对该服务有很强的参考意义,因此我将其排除在外。
你写了
坦率地说,虽然我
ExecutorService是由GC编写的-可访问性和范围是不同的东西,并且允许GC清除所有无法访问的内容;但是有一个Future<?>可以对该服务有很强的参考意义,因此我将其排除在外。
但这实际上是一个非常合理的场景,在JDK-8145304中对此进行了描述。在错误报告的示例中,ExecutorService并没有保存在局部变量中,但是局部变量本身并不能防止垃圾回收。
请注意,异常消息
Task java.util.concurrent.FutureTask@3148f668 rejected from
java.util.concurrent.ThreadPoolExecutor@6e005dc9[Terminated,
pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0]
Run Code Online (Sandbox Code Playgroud)
支持,因为的状态ThreadPoolExecutor@6e005dc9指定为Terminated。
期货参考其创建的假设ExecutorService是错误的。实际类型取决于服务实现,但对于常见的实现,它将是其实例,FutureTask而没有引用ExecutorService。这也适用于您的情况,在异常消息中也可见。
即使有引用,创建者也将是实际的ThreadPoolExecutor,但是包装FinalizableDelegatedExecutorService实例将被垃圾收集并调用shutdown()该ThreadPoolExecutor实例(瘦包装器通常是绕过包装的优化代码中过早垃圾收集的良好候选者)。
请注意,尽管错误报告仍处于打开状态,但实际上该问题已在JDK 11中解决。在那里,的基FinalizableDelegatedExecutorService类DelegatedExecutorService具有一个execute类似于以下内容的实现:
public void execute(Runnable command) {
try {
e.execute(command);
} finally { reachabilityFence(this); }
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
81 次 |
| 最近记录: |