前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >史上最全的java分布式锁的5种实现方式

史上最全的java分布式锁的5种实现方式

原创
作者头像
疯狂的KK
发布2023-03-23 12:20:19
1.4K0
发布2023-03-23 12:20:19
举报
文章被收录于专栏:Java项目实战
  1. 基于Redis实现分布式锁

Redis是一个高性能的内存数据库,支持分布式锁的实现。基于Redis实现分布式锁的步骤如下:

(1)获取Redis连接

(2)使用setnx命令设置键值对,如果返回值为1,则表示获取锁成功,否则获取锁失败

(3)如果获取锁失败,则使用get命令获取锁的值,并判断当前时间是否大于锁的超时时间,如果是,则使用getset命令设置新的锁值,并判断返回的值是否与获取的值相等,如果相等,则表示获取锁成功,否则获取锁失败

(4)使用del命令删除锁

示例代码如下:

代码语言:txt
复制
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;
        }
    }
}
  1. 基于ZooKeeper实现分布式锁

ZooKeeper是一个分布式协调服务,支持分布式锁的实现。基于ZooKeeper实现分布式锁的步骤如下:

(1)创建一个ZooKeeper客户端连接

(2)使用create命令创建一个临时节点,如果创建成功,则表示获取锁成功,否则获取锁失败

(3)如果获取锁失败,则使用exists命令监听锁节点的删除事件,并等待锁释放

(4)使用delete命令删除锁节点

示例代码如下:

代码语言:txt
复制
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. 基于数据库实现分布式锁

数据库可以通过加锁机制来实现分布式锁。基于数据库实现分布式锁的步骤如下:

(1)使用select for update命令查询锁,如果查询结果为空,则表示获取锁成功,否则获取锁失败

(2)如果获取锁失败,则使用select命令查询锁,并设置超时时间,等待锁释放

(3)使用update命令更新锁

示例代码如下:

代码语言:txt
复制
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. 基于文件系统实现分布式锁

文件系统可以通过文件锁来实现分布式锁。基于文件系统实现分布式锁的步骤如下:

(1)使用FileChannel的tryLock方法获取文件锁,如果获取锁成功,则表示获取锁成功,否则获取锁失败

(2)如果获取锁失败,则使用FileChannel的lock方法获取文件锁,并等待锁释放

(3)使用FileChannel的release方法释放文件锁

示例代码如下:

代码语言:txt
复制
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;
        }
    }
}
  1. 基于Spring实现分布式锁

Spring提供了分布式锁的实现,可以使用Spring进行分布式锁的操作。基于Spring实现分布式锁的步骤如下:

(1)使用@Lock注解标注需要加锁的方法

(2)使用@LockKey注解标注锁的键值

(3)使用@EnableLock注解开启分布式锁

示例代码如下:

代码语言:txt
复制
@EnableLock
public class SpringLock {
    
    @Lock(key = "lockKey")
    public void doSomething() {
        // do something
    }
    
    @Lock(key = "#id")
    public void doSomething(@LockKey String id) {
        // do something
    }
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档