• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

通过实例解析Java分布式锁三种实现方法

java 搞代码 4年前 (2022-01-09) 36次浏览 已收录 0个评论

分布式锁三种实现方式:

一, 基于数据库实现分布式锁

1. 悲观锁

利用select … where … for update 排他锁

注意: 其他附加功能与实现一基本一致,这里需要注意的是“where name=lock ”,name字段必须要走索引,否则会锁表。有些情况下,比如表不大,mysql优化器会不走这个索引,导致锁表问题。

2. 乐观锁

所谓乐观锁与前边最大区别在于基于CAS思想,是不具有互斥性,不会产生锁等待而消耗资源,操作过程中认为不存在并发冲突,只有update version失败后才能觉察到。我们的抢购、秒杀就是用了这种实现以防止超卖。
通过增加递增的版本号字段实现乐观锁

二, 基于缓存(Redis等)实现分布式锁

1. 使用命令介绍:

(1)SETNX

SETNX key val:当且仅当key不存在时,set一个key为val的字符串,返回1;若key存在,则什么都不做,返回0。

(2)expire

expire key timeout:为key设置一个超时时间,单位为second,超过这个时间锁会自动释放,避免死锁。

(3)delete

delete key:删除key

在使用Redis实现分布式锁的时候,主要就会使用到这三个命令。

2. 实现思想:

(1)获取锁的时候,使用setnx加锁,并使用expire命令为锁添加一个超时时间,超过该时间则自动释放锁,锁的value值为一个随机生成的UUID,通过此在释放锁的时候进行判断。

(2)获取锁的时候还设置一个获取的超时时间,若超过这个时间则放弃获取锁。

(3)释放锁的时候,通过UUID判断是不是该锁,若是该锁,则执行delete进行锁释放。

3.分布式锁的简单实现代码:

1 /**
 2 * 分布式锁的简单实现代码 4 */
 5 public class DistributedLock {
 6 
 7   private final JedisPool jedisPool;
 8 
 9   public DistributedLock(JedisPool jedisPool) {
 10     this.jedisPool = jedisPool;
 11   }
 12 
 13   /**
 14   * 加锁
 15   * @param lockName    锁的key
 16   * @param acquireTimeout 获取超时时间
 17   * @param timeout    锁的超时时间
 18   * @return 锁标识
 19   */
 20   public String lockWithTimeout(String lockName, long acquireTimeout, long timeout) {
 21     Jedis conn = null;
 22     String retIdentifier = null;
 23     try {
 24       // 获取连接
 25       conn = jedisPool.getResource();
 26       // 随机生成一个value
 27       String identifier = UUID.randomUUID().toString();
 28       // 锁名,即key值
 29       String lockKey = "lock:" + lockName;
 30       // 超时时间,上锁后超过此时间则自动释放锁
 31       int lockExpire = (int) (timeout / 1000);
 32 
 33       // 获取锁的超时时间,超过这个时间则放弃获取锁
 34       long end = System.currentTimeMillis() + acquireTimeout;
 35       while (System.currentTimeMillis() < end) {
 36         if (conn.setnx(lockKey, identifier) == 1) {
 37           conn.expire(lockKey, lockExpire);
 38           // 返回value值,用于释放锁时间确认
 39           retIdentifier = identifier;
 40           return retIdentifier;
 41         }
 42         // 返回-1代表key没有设置超时时间,为key设置一个超时时间
 43         if (conn.ttl(lockKey) == -1) {<strong>本文来源gaodai#ma#com搞@@代~&码*网2</strong>
 44           conn.expire(lockKey, lockExpire);
 45         }
 46 
 47         try {
 48           Thread.sleep(10);
 49         } catch (InterruptedException e) {
 50           Thread.currentThread().interrupt();
 51         }
 52       }
 53     } catch (JedisException e) {
 54       e.printStackTrace();
 55     } finally {
 56       if (conn != null) {
 57         conn.close();
 58       }
 59     }
 60     return retIdentifier;
 61   }
 62 
 63   /**
 64   * 释放锁
 65   * @param lockName  锁的key
 66   * @param identifier 释放锁的标识
 67   * @return
 68   */
 69   public boolean releaseLock(String lockName, String identifier) {
 70     Jedis conn = null;
 71     String lockKey = "lock:" + lockName;
 72     boolean retFlag = false;
 73     try {
 74       conn = jedisPool.getResource();
 75       while (true) {
 76         // 监视lock,准备开始事务
 77         conn.watch(lockKey);
 78         // 通过前面返回的value值判断是不是该锁,若是该锁,则删除,释放锁
 79         if (identifier.equals(conn.get(lockKey))) {
 80           Transaction transaction = conn.multi();
 81           transaction.del(lockKey);
 82           List<Object> results = transaction.exec();
 83           if (results == null) {
 84             continue;
 85           }
 86           retFlag = true;
 87         }
 88         conn.unwatch();
 89         break;
 90       }
 91     } catch (JedisException e) {
 92       e.printStackTrace();
 93     } finally {
 94       if (conn != null) {
 95         conn.close();
 96       }
 97     }
 98     return retFlag;
 99   }
100 }

搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:通过实例解析Java分布式锁三种实现方法

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址