如何同步Timer的cancel()方法,确保first()优先执行?
问题与解决方案
问题背景
需要实现Timer.cancel()后,确保first()方法优先于second()执行。原代码中,Timer调度的任务执行长耗时逻辑后调用first(),但调用print()时,timer.cancel()后直接执行second(),无法保证两者的执行顺序。尝试过空同步块方案,但该方式可读性差、不直观,并非合理方案。
问题分析
Timer.cancel()仅会终止后续任务的调度,不会中断正在运行的TimerTask线程。因此print()中的second()与TimerTask中的first()可能并发执行,导致顺序无法保证。空同步块虽然能通过锁的happens-before规则勉强实现顺序,但属于不直观的“黑魔法”,维护性极差,不推荐使用。
正确解决方案
方案1:使用CountDownLatch(推荐)
利用CountDownLatch专门等待线程任务完成的特性,明确控制执行顺序:
import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.CountDownLatch; public class TimerSyncDemo { private Timer timer; private CountDownLatch taskLatch; public void startTimer(long delayNoMatter, long veryShortInterval) { taskLatch = new CountDownLatch(1); timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { try { // 模拟长耗时任务 Thread.sleep(3000); } catch (InterruptedException e) { // 响应中断,避免任务无意义挂起 Thread.currentThread().interrupt(); return; } first(); taskLatch.countDown(); // 任务完成,释放等待信号 } }, delayNoMatter, veryShortInterval); } void first() { System.out.println("first"); } void second() { // 必须最后执行 System.out.println("second"); } void print() { timer.cancel(); // 终止后续任务调度 try { taskLatch.await(); // 等待正在运行的任务执行完first() } catch (InterruptedException e) { Thread.currentThread().interrupt(); } second(); } }
说明:
CountDownLatch初始化计数为1,TimerTask执行完first()后调用countDown()将计数减为0print()中调用await()会阻塞,直到计数为0,确保second()在first()之后执行
方案2:用ScheduledExecutorService替代Timer(更优)
Timer存在单线程局限性(单个任务异常会导致整个Timer终止),推荐使用ScheduledExecutorService替代,结合同步工具实现顺序控制:
import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.CountDownLatch; public class ExecutorSyncDemo { private ScheduledExecutorService executor; private CountDownLatch taskLatch; public void startTimer(long delayNoMatter, long veryShortInterval) { taskLatch = new CountDownLatch(1); executor = Executors.newSingleThreadScheduledExecutor(); executor.scheduleAtFixedRate(new Runnable() { @Override public void run() { try { // 模拟长耗时任务 Thread.sleep(3000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return; } first(); taskLatch.countDown(); } }, delayNoMatter, veryShortInterval, TimeUnit.MILLISECONDS); } void first() { System.out.println("first"); } void second() { System.out.println("second"); } void print() { executor.shutdown(); // 停止接受新任务 try { // 等待正在运行的任务完成,超时时间可按需调整 if (!executor.awaitTermination(5, TimeUnit.SECONDS)) { executor.shutdownNow(); // 超时后强制终止任务 } taskLatch.await(); // 确保first()已执行完毕 } catch (InterruptedException e) { executor.shutdownNow(); Thread.currentThread().interrupt(); } second(); } }
说明:
ScheduledExecutorService是Timer的官方替代方案,支持多线程调度,稳定性更强shutdown()不会中断正在运行的任务,awaitTermination()可等待任务完成,结合CountDownLatch双重保障执行顺序
内容的提问来源于stack exchange,提问作者Tarik
相关产品推荐
相关产品推荐

