在Java中,使用分布式锁可以确保在多个实例或服务器之间,相同任务在一个周期内只执行一次。以下是实现这一功能的步骤和示例代码:
步骤
- 选择分布式锁的实现:可以使用Redis、Zookeeper等来实现分布式锁。
- 获取锁:在任务开始执行之前尝试获取锁。如果成功获取到锁,则继续执行任务;如果没有获取到锁,则跳过执行。
- 释放锁:任务执行完毕后,释放锁,以便其他实例可以获取锁并执行任务。
示例代码(使用Redis作为分布式锁)
首先,添加Redis客户端依赖到你的项目中(例如使用Jedis):
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.6.0</version>
</dependency>
然后,创建一个使用Redis分布式锁的任务调度器:
import redis.clients.jedis.Jedis;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class DistributedTaskScheduler {
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
private final Jedis jedis = new Jedis("localhost", 6379); // 连接到Redis服务器
public void start() {
final Runnable task = () -> {
String lockKey = "taskLock";
long acquireTimeout = 5000; // 获取锁的超时时间(毫秒)
long lockExpiry = 60000; // 锁的过期时间(毫秒)
// 尝试获取锁
if (acquireLock(lockKey, acquireTimeout, lockExpiry)) {
try {
// 执行任务逻辑
System.out.println("Executing task at " + System.currentTimeMillis());
} finally {
// 释放锁
releaseLock(lockKey);
}
} else {
System.out.println("Failed to acquire lock, skipping task execution");
}
};
// 每分钟检查一次是否需要执行任务
scheduler.scheduleAtFixedRate(task, 0, 1, TimeUnit.MINUTES);
}
private boolean acquireLock(String lockKey, long acquireTimeout, long lockExpiry) {
long end = System.currentTimeMillis() + acquireTimeout;
while (System.currentTimeMillis() < end) {
if (jedis.setnx(lockKey, "locked") == 1) {
// 尝试设置锁
jedis.expire(lockKey, (int) (lockExpiry / 1000)); // 设置锁的过期时间
return true;
}
try {
Thread.sleep(100); // 等待一段时间后重试
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
return false;
}
private void releaseLock(String lockKey) {
jedis.del(lockKey); // 删除锁
}
public static void main(String[] args) {
DistributedTaskScheduler scheduler = new DistributedTaskScheduler();
scheduler.start();
}
}
在这个例子中,我们使用了Redis来存储锁的状态。acquireLock
方法尝试获取锁,并在成功获取后设置一个过期时间,以防止死锁的情况发生。releaseLock
方法用于释放锁。通过这种方式,我们可以确保在多个实例中,同一任务在一个周期内只被执行一次。