9、Redis分布式锁实战

在【Redis Jedis实战(含Spring Boot)】基础上做如下修改:

RedisDistributedLockApplication.java

package com.java.ashare.redis.distributedlock;

import java.util.concurrent.TimeUnit;

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.java.ashare.redis.utils.RedisUtil;

@Component
public class RedisDistributedLockApplication {

	/**
	 * 普通分布式锁
	 * 
	 * 考虑异常情况:
	 * 		1、RedisUtil.del("lockKey")之前抛出异常导致加锁key没有删除掉,后面线程无法获得锁,通过finally解决;
	 * 		2、如果加锁成功后不是抛出异常而是宕机,那么加锁key也无法删除,后面线程无法获得锁,通过设置key过期时间解决;
	 * 		3、业务执行时间大于key过期时间,那么第一个线程RedisUtil.del("lockKey")操作会把第二个线程加的锁key删除掉,那么第三个线程加锁成功,最终导致锁失效,线程不安全,出现超卖情况,
	 * 			解决方案:加锁成功后开启一个子线程执行java timer定时任务,定时重新设置过期时间,间隔时间不能超过key过期时间;
	 */
	public void decrStock() {
		
		try {
			// 加锁
			// spring-data-redis-2.1以上版本才支持setnx+expire原子操作
			Boolean result = RedisUtil.valueOperations().setIfAbsent("lockKey", "1", 10, TimeUnit.SECONDS);
			
			if(!result) {
				
				System.out.println("加锁失败!");
			} else {
				
				System.out.println("加锁成功!");
				int stock = Integer.parseInt(RedisUtil.valueOperations().get("stock"));
				if(stock > 0) {
					int realStock = stock - 1;
					RedisUtil.valueOperations().set("stock", realStock + "");
					System.out.println("扣减成功,剩余库存:" + realStock);
				} else {
					System.out.println("扣减失败,库存不足!");
				}
			}
		} finally {
			// 释放锁
			RedisUtil.del("lockKey");
		}
	}
 }

以上分布式锁实现,我们需要考虑很多东西,稍微不注意就可能在高并发环境下出现各种异常情况,怎么办呢?
有,使用Redisson实现分布式锁,封装以上逻辑,代码更加简单。
参考:【7-1、Redis Redisson分布式锁实战(含Spring Boot)】

你可能感兴趣的:(Redis)