多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
[TOC] 参考链接:[https://juejin.im/post/5b16148a518825136137c8db](https://juejin.im/post/5b16148a518825136137c8db) ## 为何需要分布式锁 * 效率:使用分布式锁可以避免不同节点重复相同的工作,这些工作会浪费资源。比如用户付了钱之后有可能不同节点会发出多封短信。 * 正确性:加分布式锁同样可以避免破坏正确性的发生,如果两个节点在同一条数据上面操作,比如多个节点机器对同一个订单操作不同的流程有可能会导致该笔订单最后状态出现错误,造成损失。 ## 分布式锁的特点 当我们确定了在不同节点上需要分布式锁,那么我们需要了解分布式锁到底应该有哪些特点: * 互斥性:和我们本地锁一样互斥性是最基本,但是分布式锁需要保证在不同节点的不同线程的互斥。 * 可重入性:同一个节点上的同一个线程如果获取了锁之后那么也可以再次获取这个锁。 * 锁超时:和本地锁一样支持锁超时,防止死锁。 * 高效,高可用:加锁和解锁需要高效,同时也需要保证高可用防止分布式锁失效,可以增加降级。 * 支持阻塞和非阻塞:和ReentrantLock一样支持lock和trylock以及tryLock(long timeOut)。 * 支持公平锁和非公平锁(可选):公平锁的意思是按照请求加锁的顺序获得锁,非公平锁就相反是无序的。这个一般来说实现的比较少。 使用redis 加锁: ``` std::string threadId = Thread.currentThread().getId() set(key,threadId,30,NX) ``` 解锁: ``` if(threadId.equals(redisClient.get(key))){ del(key) } ``` 但是,这样做又隐含了一个新的问题,**判断和释放锁是两个独立操作,不是原子性**。 我们都是追求极致的程序员,所以这一块要用Lua脚本来实现: ``` String luaScript = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";** redisClient.eval(luaScript , Collections.singletonList(key), Collections.singletonList(threadId)); ``` 这样一来,验证和删除过程就是原子操作了。