如果出现问题并且我想重试,使用同一个 Executor 重新排队 Runnable 是不是安全或可取?
Posted
技术标签:
【中文标题】如果出现问题并且我想重试,使用同一个 Executor 重新排队 Runnable 是不是安全或可取?【英文标题】:Is it safe or advisable to re-enqueue a Runnable with the same Executor if a problem occurs and I want to retry?如果出现问题并且我想重试,使用同一个 Executor 重新排队 Runnable 是否安全或可取? 【发布时间】:2011-06-29 09:55:42 【问题描述】:我刚刚在我的runnable的run()
方法中写了这段代码:
try
dbConnection = MyApp.datasource.getConnection();
catch (SQLException e)
logger.log(Level.SEVERE, "Could not obtain a DB connection! Re-enqueuing this task. Message: " + e.getMessage(), e);
MyApp.executor.execute(this);
return;
如您所见,如果任务无法获得数据库连接,它应该重新排队,进入它运行前所在的同一队列。
我认为这可能是安全的,但感觉很有趣,我只是想确保没有任何我遗漏的问题。
谢谢!
【问题讨论】:
也许你想在重新排队之前添加一些Thread.sleep()
。否则,如果 getConnection() 快速失败,您将产生大量 CPU 负载(并且可能由于日志记录导致 I/O 负载)。
【参考方案1】:
就执行者而言,这很好。
但请记住,失败可能会很快发生,然后执行器可能会快速重新运行您的代码。这可能会导致消耗大量 CPU 而没有任何结果。
内置强制重试延迟和最大循环计数。
【讨论】:
【参考方案2】:有发生所谓的中毒消息的风险:如果SQLException
无法逃脱,任务将无限重复。您必须提供某种计数器或计时器。
根据执行程序的占用情况(已经调度了多少并发任务),重试之间的间隔可能会有很大差异。您可能会使用 100% 的 CPU,或者等待重试很长时间。
如果偶然地,您的 父 任务(重新调度自身的任务)等待 子(重新调度)调用的结果,当执行器仅在一个线程上运行时,您可能会遇到死锁。
您正在使用 MyApp
的原始字段,这似乎是一个糟糕的模式。
至于总体思路:为什么不在run()
中设置一个循环?您想对正在执行的其他任务更加“公平”吗?
【讨论】:
以上是关于如果出现问题并且我想重试,使用同一个 Executor 重新排队 Runnable 是不是安全或可取?的主要内容,如果未能解决你的问题,请参考以下文章