Nat*_*ger 4 java concurrency resources
我试图了解如何确保特定操作在一定时间内完成.对于java的新util.concurrent库来说,这似乎是一个简单的工作.但是,此任务声明与数据库的连接,我想确保它在超时时正确释放该连接.
所以要打电话给服务:
int resultCount = -1;
ExecutorService executor = null;
try {
 executor = Executors.newSingleThreadExecutor();
 FutureTask<Integer> task = new CopyTask<Integer>();
 executor.execute(task);
 try {
  resultCount = task.get(2, TimeUnit.MINUTES);
 } catch (Exception e) {
   LOGGER.fatal("Migrate Events job crashed.", e);
   task.cancel(true);
   return;
 }
} finally {
if (executor != null) {
 executor.shutdown();
}
Run Code Online (Sandbox Code Playgroud)
任务本身只是包含一个可调用的,这里是调用方法:
@Override
public Integer call() throws Exception {
 Session session = null;
 try {
  session = getSession();
  ... execute sql against sesssion ...
  }
 } finally {
  if (session != null) {
   session.release();
  }
 }
}
Run Code Online (Sandbox Code Playgroud)
所以,我对那些已经做到这一点的人的问题是:在由于TimeoutException导致任务失败的情况下,会调用session.release()吗?我假设它不是,但我希望被证明是错的.
谢谢
编辑:我遇到的问题是,由于奇怪的数据库问题,有问题的sql偶尔没有完成.所以,我想要做的只是关闭连接,让db回滚事务,休息一下,然后再重新尝试.所以我把get(...)视为杀死thead.那是错的吗?
And*_*yle 11
当您task.get()使用超时调用时,该超时仅适用于尝试获取结果(在当前线程中),而不适用于计算本身(在工作线程中).因此你的问题在这里; 如果一个工作线程进入一个永远不会返回的状态,那么超时只会确保你的轮询代码继续运行,但不会影响工作者.
你task.cancel(true)在catch块中的调用是我最初建议的,这是很好的编码实践.不幸的是,这只会在线程上设置一个标志,该标志可能/应该由行为良好的长时间运行,可取消的任务检查,但它不会对其他线程采取任何直接操作.如果SQL执行方法没有声明它们抛出InterruptedException,那么它们不会检查这个标志,并且不会通过典型的Java机制中断.
真的这一切归结为一个事实,即在工作线程的代码必须支持停止某种机制本身,如果它的运行时间过长.支持标准中断机制是这样做的一种方式; 间歇性地检查一些布尔标志,或其他定制的替代品,也会起作用.但是,没有保证的方法可以导致另一个线程返回(缺少Thread.stop,这是有充分理由弃用的).您需要与正在运行的代码进行协调,以便以一种它会注意到的方式发出信号.
在这种特殊情况下,我希望你可以在数据库连接上设置一些参数,以便SQL调用在给定的时间段后超时,这意味着控制返回到你的Java代码(可能有一些例外),所以最后块被调用.如果没有,即PreparedStatement.execute()在某个预定时间之后无法进行数据库调用(例如)返回控制,那么您需要在Callable中生成一个额外的线程,该线程可以监视超时并强制关闭连接/会话(如果它)到期.这不是很好,如果你可以得到SQL调用合作,你的代码会更清晰.
(具有讽刺意味的是,尽管你提供了大量的代码来支持这个问题,但真正重要的部分是你编辑的那个部分:" ... execute sql against sesssion ...":-))