史上最全的java分布式锁的5种实现方式
- 基于Redis实现分布式锁
Redis是一个高性能的内存数据库,支持分布式锁的实现。基于Redis实现分布式锁的步骤如下:
(1)获取Redis连接
(2)使用setnx命令设置键值对,如果返回值为1,则表示获取锁成功,否则获取锁失败
(3)如果获取锁失败,则使用get命令获取锁的值,并判断当前时间是否大于锁的超时时间,如果是,则使用getset命令设置新的锁值,并判断返回的值是否与获取的值相等,如果相等,则表示获取锁成功,否则获取锁失败
(4)使用del命令删除锁
示例代码如下:
public class RedisLock {
private Jedis jedis;
private String lockKey;
private int expireTime = 30000;
private int timeout = 10000;
private boolean locked = false;
public RedisLock(Jedis jedis, String lockKey) {
this.jedis = jedis;
this.lockKey = lockKey;
}
public boolean lock() throws InterruptedException {
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < timeout) {
long expires = System.currentTimeMillis() + expireTime + 1;
String expiresStr = String.valueOf(expires);
if (jedis.setnx(lockKey, expiresStr) == 1) {
locked = true;
return true;
}
String currentValueStr = jedis.get(lockKey);
if (currentValueStr != null && Long.parseLong(currentValueStr) < System.currentTimeMillis()) {
String oldValueStr = jedis.getSet(lockKey, expiresStr);
if (oldValueStr != null && oldValueStr.equals(currentValueStr)) {
locked = true;
return true;
}
}
Thread.sleep(1000);
}
return false;
}
public void unlock() {
if (locked) {
jedis.del(lockKey);
locked = false;
}
}
}
- 基于ZooKeeper实现分布式锁
ZooKeeper是一个分布式协调服务,支持分布式锁的实现。基于ZooKeeper实现分布式锁的步骤如下:
(1)创建一个ZooKeeper客户端连接
(2)使用create命令创建一个临时节点,如果创建成功,则表示获取锁成功,否则获取锁失败
(3)如果获取锁失败,则使用exists命令监听锁节点的删除事件,并等待锁释放
(4)使用delete命令删除锁节点
示例代码如下:
public class ZooKeeperLock implements Watcher {
private ZooKeeper zooKeeper;
private String lockPath;
private String lockNode;
private CountDownLatch countDownLatch = new CountDownLatch(1);
private boolean locked = false;
public ZooKeeperLock(ZooKeeper zooKeeper, String lockPath) {
this.zooKeeper = zooKeeper;
this.lockPath = lockPath;
}
public boolean lock() throws InterruptedException, KeeperException {
lockNode = zooKeeper.create(lockPath + "/lock-", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
List<String> nodes = zooKeeper.getChildren(lockPath, false);
Collections.sort(nodes);
if (lockNode.equals(lockPath + "/" + nodes.get(0))) {
locked = true;
return true;
} else {
String prevNode = lockPath + "/" + nodes.get(Collections.binarySearch(nodes, lockNode.substring(lockNode.lastIndexOf("/") + 1)) - 1);
zooKeeper.exists(prevNode, this);
countDownLatch.await();
return locked;
}
}
public void unlock() throws InterruptedException, KeeperException {
zooKeeper.delete(lockNode, -1);
locked = false;
}
@Override
public void process(WatchedEvent event) {
if (event.getType() == Event.EventType.NodeDeleted) {
countDownLatch.countDown();
}
}
}
- 基于数据库实现分布式锁
数据库可以通过加锁机制来实现分布式锁。基于数据库实现分布式锁的步骤如下:
(1)使用select for update命令查询锁,如果查询结果为空,则表示获取锁成功,否则获取锁失败
(2)如果获取锁失败,则使用select命令查询锁,并设置超时时间,等待锁释放
(3)使用update命令更新锁
示例代码如下:
public class DatabaseLock {
private Connection connection;
private String lockTable;
private String lockName;
private int expireTime = 30000;
private int timeout = 10000;
private boolean locked = false;
public DatabaseLock(Connection connection, String lockTable, String lockName) {
this.connection = connection;
this.lockTable = lockTable;
this.lockName = lockName;
}
public boolean lock() throws SQLException, InterruptedException {
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < timeout) {
PreparedStatement selectStatement = connection.prepareStatement("SELECT * FROM " + lockTable + " WHERE name = ? FOR UPDATE");
selectStatement.setString(1, lockName);
ResultSet resultSet = selectStatement.executeQuery();
if (!resultSet.next()) {
PreparedStatement insertStatement = connection.prepareStatement("INSERT INTO " + lockTable + " (name, expires) VALUES (?, ?)");
insertStatement.setString(1, lockName);
insertStatement.setTimestamp(2, new Timestamp(System.currentTimeMillis() + expireTime));
insertStatement.executeUpdate();
locked = true;
return true;
}
Timestamp expires = resultSet.getTimestamp("expires");
if (expires != null && expires.getTime() < System.currentTimeMillis()) {
PreparedStatement updateStatement = connection.prepareStatement("UPDATE " + lockTable + " SET expires = ? WHERE name = ? AND expires = ?");
updateStatement.setTimestamp(1, new Timestamp(System.currentTimeMillis() + expireTime));
updateStatement.setString(2, lockName);
updateStatement.setTimestamp(3, expires);
int affectedRows = updateStatement.executeUpdate();
if (affectedRows > 0) {
locked = true;
return true;
}
}
Thread.sleep(1000);
}
return false;
}
public void unlock() throws SQLException {
if (locked) {
PreparedStatement deleteStatement = connection.prepareStatement("DELETE FROM " + lockTable + " WHERE name = ?");
deleteStatement.setString(1, lockName);
deleteStatement.executeUpdate();
locked = false;
}
}
}
- 基于文件系统实现分布式锁
文件系统可以通过文件锁来实现分布式锁。基于文件系统实现分布式锁的步骤如下:
(1)使用FileChannel的tryLock方法获取文件锁,如果获取锁成功,则表示获取锁成功,否则获取锁失败
(2)如果获取锁失败,则使用FileChannel的lock方法获取文件锁,并等待锁释放
(3)使用FileChannel的release方法释放文件锁
示例代码如下:
public class FileLock {
private FileChannel fileChannel;
private FileLock lock;
private boolean locked = false;
public FileLock(File file) throws IOException {
fileChannel = new RandomAccessFile(file, "rw").getChannel();
}
public boolean lock() throws IOException, InterruptedException {
lock = fileChannel.tryLock();
if (lock != null) {
locked = true;
return true;
} else {
lock = fileChannel.lock();
lock = fileChannel.tryLock();
locked = true;
return true;
}
}
public void unlock() throws IOException {
if (locked) {
lock.release();
fileChannel.close();
locked = false;
}
}
}
- 基于Spring实现分布式锁
Spring提供了分布式锁的实现,可以使用Spring进行分布式锁的操作。基于Spring实现分布式锁的步骤如下:
(1)使用@Lock注解标注需要加锁的方法
(2)使用@LockKey注解标注锁的键值
(3)使用@EnableLock注解开启分布式锁
示例代码如下:
@EnableLock
public class SpringLock {
@Lock(key = "lockKey")
public void doSomething() {
// do something
}
@Lock(key = "#id")
public void doSomething(@LockKey String id) {
// do something
}
}
- 点赞
- 收藏
- 关注作者
评论(0)