Liferay 7.1 如何终止调度任务中正在执行的线程
问题根因说明
你当前加的synchronized关键字未生效,核心原因是每次任务触发都会new RunnableService()创建新实例,synchronized是对象级锁,不同实例的锁互不干扰,因此完全起不到互斥作用。
方案1:禁用任务并发执行(推荐)
Liferay 7.x 原生支持定时任务并发控制,无需手动改造业务代码,仅需在任务的@Component注解中添加禁用并发的配置即可:
@Component( immediate = true, property = { "cron.expression=0 5 10 * * ? *", "scheduler.concurrent:Boolean=false" }, service = CustomJob.class ) public class CustomJob extends BaseMessageListener { // 原有逻辑无需修改 }
添加该配置后,Liferay的调度器会自动检测上一次任务是否执行完成,未完成的情况下不会触发新的任务实例,完全避免并发问题,也不会出现硬终止任务导致的资源泄漏、数据不一致问题。
方案2:手动终止前一次任务(不推荐)
如果你的业务场景确实需要强制终止前一次未完成的任务再启动新任务,可以通过存储运行线程、主动发送中断信号实现,注意需要业务逻辑主动响应中断信号:
改造CustomJob代码
@Component( immediate = true, property = {"cron.expression=0 5 10 * * ? *"}, service = CustomJob.class ) public class CustomJob extends BaseMessageListener { // 存储当前正在运行的任务线程,用volatile保证可见性 private volatile Thread runningThread; private final Object lock = new Object(); @Override protected void doReceive(Message message) throws Exception { synchronized (lock) { // 前一次任务仍在运行,先中断 if (runningThread != null && runningThread.isAlive()) { runningThread.interrupt(); // 等待前一次线程终止,可根据需求调整超时时间 runningThread.join(30000); } RunnableService rs = new RunnableService(); runningThread = new Thread(rs); runningThread.start(); } } }
改造RunnableService代码,响应中断
public class RunnableService implements Runnable { @Override public void run() { // 业务逻辑的每个耗时步骤前都要检查中断信号 if (Thread.currentThread().isInterrupted()) { // 释放已占用的资源后直接返回 return; } // 示例:循环处理逻辑中也要检查中断 for (int i = 0; i < 100; i++) { if (Thread.currentThread().isInterrupted()) { return; } // 执行业务逻辑 } } }
注意:如果业务逻辑不响应中断信号,调用interrupt()方法不会终止线程,仅会标记中断状态,因此该方案需要配合业务逻辑改造使用,否则无法生效
内容的提问来源于stack exchange,提问作者DyM
相关产品推荐
相关产品推荐

