乐观锁基于
CAS
(
Compare And Swap
)思想(比较并替换),是不具有互斥性,不会产生锁等待而消 耗资源,但是需要反复的重试,但也是因为重试的机制,能比较快的响应。因此我们可以利用redis
来实 现乐观锁。具体思路如下:
1
、利用
redis
的
watch
功能,监控这个
redisKey
的状态值
2
、获取
redisKey
的值
3
、创建
redis
事务
4
、给这个
key
的值
+1
5
、然后去执行这个事务,如果
key
的值被修改过则回滚,
key
不加
1
下面用一个秒杀的案例去演示:
public class Second {
/**
* 使用乐观锁实现秒杀
*
* @param args
*/
public static void main(String[] args) {
String redisKey = "lock";
ExecutorService executorService = Executors.newFixedThreadPool(20);
try {
Jedis jedis = new Jedis("xxxxxxxx", 6379);
jedis.auth("xxxx");
//初始值
jedis.set(redisKey, "0");
jedis.close();
} catch (Exception e) {
e.printStackTrace();
}
for (int i = 0; i < 1000; i++) {
executorService.execute(() ->{
Jedis jedis1 = new Jedis("xxxxxx", 6379);
jedis1.auth("xxxx");
try {
jedis1.watch(redisKey);
String redisValue = jedis1.get(redisKey);
Integer valInteger = Integer.valueOf(redisValue);
String userInfo = UUID.randomUUID().toString();
//没有秒完
if (valInteger < 10) {
Transaction tx = jedis1.multi();
tx.incr(redisKey);
List<Object> list = tx.exec();
//秒成功 失败返回空list而不是空
if (list != null && list.size() > 0) {
System.out.println("用户:" + userInfo + ",秒杀成功!当前成功人数:" + (valInteger + 1));
}
//版本变化,被别人抢了。
else {
System.out.println("用户:" + userInfo + ",秒杀失败");
}
}
//秒完了
else {
System.out.println("已经有10人秒杀成功,秒杀结束");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
jedis1.close();
}
});
}
executorService.shutdown();
}
}
//打印日志如下
用户:05d4771f-82ef-4435-98ca-d9e21e60ae46,秒杀失败
用户:987c172a-13d6-469c-ab28-3205ce6fde70,秒杀失败
用户:3dbe8630-171e-4635-a94a-27741c5b2ba2,秒杀成功!当前成功人数:10
已经有10人秒杀成功,秒杀结束
用户:893396ff-40a1-4d75-b957-f5f07310a459,秒杀失败
已经有10人秒杀成功,秒杀结束
用户:cc62637c-af35-4281-8597-f13b2661936f,秒杀失败
已经有10人秒杀成功,秒杀结束
用户:0950e862-883b-420c-b8db-4a70b8dc4886,秒杀失败
用户:7d95ccda-1753-40a0-aa92-60f1cdeb42e2,秒杀失败
已经有10人秒杀成功,秒杀结束
已经有10人秒杀成功,秒杀结束
已经有10人秒杀成功,秒杀结束
用户:d88a9db2-cbf1-4a45-a2b7-edb082279ebf,秒杀失败
用户:202b2a78-4857-4e56-a9a0-5fdcce443fa9,秒杀失败
已经有10人秒杀成功,秒杀结束