synchronized本身不能定时,仅保证同一时刻一个线程执行临界区;用于防重叠时需配合volatile标志位或ReentrantLock.tryLock()实现非阻塞跳过,避免调度线程阻塞。

synchronized 本身不能实现定时任务,也不能直接“定时”,它只是保证同一时刻最多一个线程执行某段代码。想用它来防止定时任务重叠执行,核心思路是:**让每次触发的任务在进入实际业务逻辑前,先尝试获取同一个锁;若锁已被占用(上一次还没执行完),就跳过本次执行或等待——但“跳过”更常见且合理,因为定时任务通常不希望堆积或阻塞调度线程。
为什么不能直接用 synchronized 方法?
如果只写 public synchronized void doTask() { ... },看似能防重入,但要注意:
- 定时框架(如 Spring 的
@Scheduled)每次触发都会新建一个调用上下文,synchronized 锁的是当前对象实例(this)——只要所有定时调用都作用于同一个 Bean 实例,这个锁才有效; - 但更关键的问题是:synchronized 是**可重入、阻塞式**的。如果上一次任务卡住或耗时很长,下一次调度线程会一直阻塞在锁上,可能拖垮整个调度器(尤其使用单线程 ScheduledExecutorService 时);
- 这不是“防重叠”,而是“强制串行+可能阻塞”,不符合“防重叠执行”的本意(即:正在跑就不启新的)。
推荐做法:synchronized + 尝试获取锁(非阻塞)
Java 没有内置的“tryLock”给普通 synchronized,但可以用 ReentrantLock 替代,它支持 tryLock()。不过如果你坚持用 synchronized,有一个轻量级技巧:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 用一个静态或实例级别的 boolean 标志位 + synchronized 块控制;
- 进入任务时先检查标志,为 true 则说明已在运行,直接 return;
- 为 false 则设为 true,执行任务,finally 中重置为 false。
示例(Spring @Scheduled 场景):
立即学习“Java免费学习笔记(深入)”;
@Component
public class MyTask {
private volatile boolean isRunning = false;
@Scheduled(fixedDelay = 5000)
public void run() {
if (!isRunning) {
synchronized (this) {
if (!isRunning) { // 双重检查
isRunning = true;
try {
// ✅ 执行真正的业务逻辑(如数据库处理、HTTP 调用等)
doActualWork();
} finally {
isRunning = false;
}
}
}
} else {
// ? 本次跳过,可打日志:任务仍在运行,跳过本次调度
System.out.println("Task skipped: already running");
}
}
private void doActualWork() {
// 模拟耗时操作
try { Thread.sleep(8000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
}
}
更健壮的替代方案:用 ReentrantLock.tryLock()
比 volatile + synchronized 更清晰、更可靠(避免指令重排和可见性边界问题):
@Component
public class MyTask {
private final ReentrantLock lock = new ReentrantLock();
@Scheduled(fixedDelay = 5000)
public void run() {
if (lock.tryLock()) {
try {
doActualWork();
} finally {
lock.unlock();
}
} else {
System.out.println("Task skipped: lock not available");
}
}
private void doActualWork() {
try { Thread.sleep(8000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
}
}
✅ tryLock() 瞬间返回 true/false,绝不阻塞调度线程;
✅ 支持中断、超时等高级控制;
✅ 语义明确:拿不到锁就放弃,完美契合“防重叠”需求。
注意事项与边界情况
- 确保锁对象(
this或lock)在所有定时调用中是同一个实例(Spring 默认单例,没问题); - 如果任务抛异常未走到 finally,volatile 方式会永久卡死(
isRunning = true再也不变),而 ReentrantLock 在未 unlock 时 JVM 不会自动释放,但你可以用try-finally严格保障; - 分布式环境?synchronized 和 ReentrantLock 都只在单 JVM 内有效,跨机器需用 Redis 分布式锁或数据库 for update 等方案;
- 不要在 synchronized 块里做远程调用或长阻塞操作——虽不破坏防重叠,但会拖慢后续调度响应。

















