这篇文章主要讲解了“SpringBoot中如何使用Redis作为全局锁”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“SpringBoot中如何使用Redis作为全局锁”吧!
public class CommonConsumerService {
//库存个数
static int goodsCount = 900;
//卖出个数
static int saleCount = 0;
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 1000; i++) {
new Thread(() -> {
try {Thread.sleep(2);} catch (InterruptedException e) {}
if (goodsCount > 0) {
goodsCount--;
System.out.println("剩余库存:" + goodsCount + " 卖出个数" + ++saleCount);
}
}).start();
}
Thread.sleep(3000);
}
}
运行一次,最后几行的输出结果如下,很明显出错了,剩余0个商品却只卖出了899个商品,很明显有商品被某个线程私吞了。
...
剩余库存:5 卖出个数893
剩余库存:5 卖出个数894
剩余库存:4 卖出个数895
剩余库存:2 卖出个数896
剩余库存:2 卖出个数897
剩余库存:1 卖出个数898
剩余库存:0 卖出个数899
redis是单线程的,串行执行,那么接下来使用redis为资源进行加锁。
1.首先引入依赖
compile "org.springframework.boot:spring-boot-starter-data-redis"
2.引入redis加锁工具类
package com.kingboy.common.utils;
import redis.clients.jedis.Jedis;
import java.util.Collections;
/**
* @author kingboy--KingBoyWorld@163.com
* @date 2017/12/29 下午1:57
* @desc Redis工具.
*/
public class RedisTool {
private static final String LOCK_SUCCESS = "OK";
private static final String SET_IF_NOT_EXIST = "NX";
private static final String SET_WITH_EXPIRE_TIME = "PX";
private static final Long RELEASE_SUCCESS = 1L;
/**
* 尝试获取分布式锁
* @param jedis Redis客户端
* @param lockKey 锁
* @param requestId 请求标识
* @param expireTime 超期时间
* @return 是否获取成功
*/
public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) {
String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
if (LOCK_SUCCESS.equals(result)) {
return true;
}
return false;
}
/**
* 释放分布式锁
* @param jedis Redis客户端
* @param lockKey 锁
* @param requestId 请求标识
* @return 是否释放成功
*/
public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) {
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
if (RELEASE_SUCCESS.equals(result)) {
return true;
}
return false;
}
}
3.将上面没有锁的示例代码改编如下:
public class RedisLockConsumerService {
//库存个数
static int goodsCount = 900;
//卖出个数
static int saleCount = 0;
@SneakyThrows
public static void main(String[] args) {
JedisPool jedisPool = new JedisPool(new JedisPoolConfig(), "192.168.0.130", 6379, 1000);
for (int i = 0; i < 1000; i++) {
new Thread(() -> {
try {Thread.sleep(2);} catch (InterruptedException e) {}
Jedis jedis = jedisPool.getResource();
boolean lock = false;
while (!lock) {
lock = RedisTool.tryGetDistributedLock(jedis, "goodsCount", Thread.currentThread().getName(), 10);
}
if (lock) {
if (goodsCount > 0) {
goodsCount--;
System.out.println("剩余库存:" + goodsCount + " 卖出个数" + ++saleCount);
}
}
RedisTool.releaseDistributedLock(jedis, "goodsCount", Thread.currentThread().getName());
jedis.close();
}).start();
}
Thread.sleep(3000);
jedisPool.close();
}
}
执行几次程序输出结果如下,可以看到结果是有序,并且正确的。
...
剩余库存:6 卖出个数894
剩余库存:5 卖出个数895
剩余库存:4 卖出个数896
剩余库存:3 卖出个数897
剩余库存:2 卖出个数898
剩余库存:1 卖出个数899
剩余库存:0 卖出个数900
感谢各位的阅读,以上就是“SpringBoot中如何使用Redis作为全局锁”的内容了,经过本文的学习后,相信大家对SpringBoot中如何使用Redis作为全局锁这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。