我有一个spring MVC应用程序,用户可以通过按钮点击启动报告生成。这个过程可能需要几分钟~10-20分钟。 我在服务调用周围使用了spring @Async注释,以便异步发生报告。当我向用户弹出一条消息,表明当前正在运行作业。 现在我想要做的是,如果另一个用户(管理员)可以通过按钮启动报告生成,该按钮应该取消/停止当前运行的@Async任务并重新启动新任务。 为此,我打电话给
.. ..
future = getCurrentTask(id); // returns the current task for given report id
if (!future.isDone())
future.cancel(true);
service.generateReport(id);
如何使“service.generateReport”在将来取消任务杀死所有正在运行的线程时等待? 根据文档,在我调用future.cancel(true)之后,isDone将返回true,而isCancelled将返回true。所以没有办法知道这份工作真的被取消了。
我只能在取消或完成旧报告时启动新报告生成,以免污染数据。
答案 0 :(得分:2)
从documentation关于cancel()
方法,
如果此方法返回true,则后续对isCancelled()的调用将始终返回
试试这个。
future = getCurrentTask(id); // returns the current task for given report id
if (!future.isDone()){
boolean terminatedImmediately=future.cancel(true);
if(terminatedImmediately)
service.generateReport(id);
else
//Inform user existing job couldn't be stopped.And to try again later
}
答案 1 :(得分:0)
假设上面的代码在线程A中运行,并且您最近取消的报告在线程B中运行,那么您需要线程A在service.generateReport(id)
之前停止并等待线程B完成/取消。
实现这一目标的一种方法是使用信号量。假设只能同时运行一个报告,首先创建一个所有线程都可访问的信号量对象(通常在报告运行器服务类上)
Semaphore semaphore = new Semaphore(1);
在代码中您需要运行报告的任何位置,请调用acquire()
方法。此方法将阻止,直到有许可证可用。同样,当报告执行完成/取消时,请确保调用release()
。释放方法将释放许可证并唤醒其他等待线程。
semaphore.acquire();
// run report..
semaphore.release();