Java 垃圾收集似乎关闭了本地执行器并导致RejectedExecutionException
间歇性头痛需要帮助。代码正在调用Java 垃圾收集似乎关闭了本地执行器并导致RejectedExecutionException,java,multithreading,garbage-collection,jvm,google-http-client,Java,Multithreading,Garbage Collection,Jvm,Google Http Client,间歇性头痛需要帮助。代码正在调用com.google.api.client.http.HttpRequest#executeAsync(),其基本逻辑如下: @Beta public Future<HttpResponse> executeAsync(Executor executor) { FutureTask<HttpResponse> future = new FutureTask<HttpResponse>(new Callable&l
com.google.api.client.http.HttpRequest#executeAsync()
,其基本逻辑如下:
@Beta
public Future<HttpResponse> executeAsync(Executor executor) {
FutureTask<HttpResponse> future = new FutureTask<HttpResponse>(new Callable<HttpResponse>() {
public HttpResponse call() throws Exception {
return execute();
}
});
executor.execute(future);
return future;
}
@Beta
public Future<HttpResponse> executeAsync() {
return executeAsync(Executors.newSingleThreadExecutor());
}
根据我的理解,GC不应该清理这个执行器,因为它还没有超出范围,但根据错误日志判断,这似乎就是行为
编辑:感谢您的快速回复。我可能需要澄清,我也不能随意复制这个,否则我可能会有更多的线索。代码通常运行良好,但这种错误很少发生,我们所拥有的只是我为症状粘贴的日志信息
我粘贴的代码不是我的。这是我正在使用的开源库
googlehtpjava客户端
。所以我没有办法改变这一点。我当然可以自己创建一个长期的执行器
,并用第一个方法调用它,但我正在努力了解目前的问题是什么 返回的ExecutorService
恰好是ThreadPoolExecutor
包装在一个FinalizableDelegatedExecutorService
中,这是一个关闭其包装的ExecutorService
的实现详细信息。我们可以从您的日志中得知执行器已关闭
[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0]
但是,为什么要最终确定目标?你说
根据我的理解GC不应该清理这个执行者因为它
还没有超出范围,但根据错误日志判断
这似乎是一种行为
这是一种常见的误解。是一种编译时特性,用于确定在何处可以使用名称引用源代码中的某个实体。它与运行时垃圾收集无关
垃圾收集(和终结)由对象的可达性控制
当对象不再被引用时,可以由
垃圾收集器。如果对象声明终结器,则终结器为
在回收对象之前执行,以给对象最后一次
有机会清理否则不会释放的资源。
当不再需要某个类时,可以将其卸载
JVM不会对对象进行垃圾收集
可访问对象是可以从任何活动线程在任何可能的连续计算中访问的任何对象
正如(Oracle开发人员)对此问题的公认答案中所述
FinalizableDelegatedExecutorService
(及其ThreadPoolExecutor
)。该操作将关闭执行器,并在提交任务时抛出RejectedExecutionException
这是该实现中的一个已知问题,是为了讨论解决方案(本质上只是更好的文档)
如果由我决定,googlehttp客户端
会将其实现更改为使用未使用FinalizableDelegatedExecutorService
包装的实现。(我已经开始讨论图书馆的解决方案。)
我的建议是创建自己的ExecutorService
(可能使用newFixedThreadPool
)并使用重载的executeAsync(Executor)
方法
问题已解决,请参阅。什么关闭您的
执行器
?如果你向数千个休眠线程发送垃圾邮件,则很可能会出现问题。我无法使用此代码重现你的问题。在对Executor调用shutdown()后,你是否以某种方式提交了新任务?@SotiriosDelimanolis,我可能指的是生命周期,或者抱歉,也许我不擅长官方术语。我认为在本例中,一旦executeAsync()
完成,执行器就可以自由地让GC执行(在执行器的终结器中调用shutdown)。但是当异常发生时,executor仍在使用中,因此GC绝对不应该触碰它并导致它关闭,对吗?@jwils请注意,这部分不是由我控制的,而是我正在使用的google http客户端。作为一个用户,我只需在我的代码中调用executeAsync()
,所使用的执行器就完全在这个HttpRequest
类中。我来寻求答案,得到了答案,还上了一堂小课。希望我能给你两个接受,谢谢!还有:“优化程序的转换可以设计为减少可访问对象的数量,使其少于那些天真地认为可访问的对象。[…]另一个例子是,如果对象字段中的值存储在寄存器中,则会出现这种情况。然后,程序可能会访问寄存器而不是对象,并且不再访问该对象。这意味着该对象是垃圾。[…]”顺便说一下,如果我事先知道只会安排一个作业,我宁愿使用executeAsync(r->newthread(r.start())代码>这意味着自动清理,而不存在提前完成的风险…是另一个抵消这些优化的选项
[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0]