引言
分布式锁是一种用于协调不同进程或线程对共享资源的访问控制的机制。在分布式系统中,由于多个节点可能同时访问或修改同一资源,因此需要一个中心化的协调机制来确保资源的访问是有序的,避免数据不一致的问题。
分布式锁的特性:
互斥性
任意时刻,只有一个客户端能持有锁。
可重入性
同一个客户端可以多次获取同一把锁。
超时释放
持有锁的客户端在一定时间内没有主动释放锁,锁应该会被自动释放,防止死锁。
容错性
分布式锁服务要有容错机制,不会因为某个节点故障而导致锁失效。
实现方式
分布式锁有多种实现方式,以下列举了几种常见的实现方式及其在Java中的代码示例:
1. 基于Redis实现
利用Redis的setnx命令可以很容易地实现分布式锁。
2. 基于Zookeeper实现
利用Zookeeper的顺序临时节点和Watcher机制可以实现分布式锁。
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.ZooDefs.Ids;
import java.util.concurrent.CountDownLatch;
public class ZookeeperDistributedLock implements Watcher {
private final ZooKeeper zk;
private final String lockPath;
private final CountDownLatch latch = new CountDownLatch(1);
public ZookeeperDistributedLock(ZooKeeper zk, String lockPath) { this.zk = zk; this.lockPath = lockPath;
} public void acquire() throws Exception { if (zk.exists(lockPath, false) != null) { zk.exists(lockPath, true, this); latch.await(); } else { zk.create(lockPath, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL); }
} @Override
public void process(WatchedEvent event) { if (event.getPath().equals(lockPath) && event.getType() == WatchedEvent.EventType.NodeDeleted) { latch.countDown(); }
} public void release() throws Exception { zk.delete(zk.getCurrentEphemeralNode(lockPath), -1);
}
}
使用示例:
以下是一个基于Redis实现的分布式锁的使用示例:
import redis.clients.jedis.Jedis;
public class DistributedLockExample {
public static void main(String[] args) {
// 初始化Redis连接
Jedis jedis = new Jedis(“localhost”, 6379);
复制代码
// 定义锁的名称和过期时间
String lockKey = “myLock”;
int expireTime = 10 * 1000; // 10秒
// 创建分布式锁对象
RedisDistributedLock lock = new RedisDistributedLock(jedis, lockKey, expireTime); try { // 尝试获取锁 if (lock.tryLock()) { try { // 成功获取锁,执行临界区代码 System.out.println("Acquired lock, executing critical section..."); // 模拟耗时操作 Thread.sleep(5000); } finally { // 释放锁 lock.unlock(); } } else { // 获取锁失败,处理获取锁失败的逻辑 System.out.println("Failed to acquire lock, doing something else..."); }
} catch (Exception e) { e.printStackTrace();
} finally { // 关闭Redis连接 if (jedis != null) { jedis.close(); }
}
}