packagecom.example.demo;importorg.apache.commons.lang3.StringUtils;importorg.slf4j.LoggerFactory;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.data.redis.core.StringRedisTemplate;importorg.springframework.stereotype.Component;importjava.util.concurrent.TimeUnit;
@Componentpublic classDistributedLockComponent {
@Autowired
StringRedisTemplate stringRedisTemplate;private org.slf4j.Logger logger = LoggerFactory.getLogger(this.getClass());/***
* @desc 加锁
*@paramkey
*@paramvalue
*@paramtimeout 超时时间
*@paramautoReleaseTime 自动释放锁时间*/
public boolean lock(String key, String value, long timeout, longautoReleaseTime) {boolean flag = true;long time =System.currentTimeMillis();long maxTime = time +timeout;//自旋等待-如果在指定时间内还没获取到锁就退出自旋,并且设置过期时间避免死锁。
while (!stringRedisTemplate.opsForValue().setIfAbsent(key, value) && time <=maxTime) {try{
TimeUnit.MICROSECONDS.sleep(10);
}catch(InterruptedException e) {
Thread.currentThread().interrupt();
flag= false;break;
}
time=System.currentTimeMillis();
}//设置过期时间
if(flag) {
stringRedisTemplate.expire(key, autoReleaseTime, TimeUnit.MILLISECONDS);
}returnflag;
}/***
* @desc 解锁
*@paramkey
*@paramvalue*/
public voidunLock(String key, String value) {try{if(StringUtils.isNotBlank(stringRedisTemplate.opsForValue().get(key))&&stringRedisTemplate.opsForValue().get(key).equals(value)) {
stringRedisTemplate.delete(key);
}
}catch(Exception e) {
logger.error(e.getMessage(), e);
}
}/*** 扣减库存*/
publicString decreaseStock(String key, String value){try{
lock(key,value,6000,6000 * 2);
}catch(Exception e){
logger.error(e.getMessage(),e);
}finally{
unLock(key,value);
}return "";
}/*** 测试可模拟多个线程扣减库存
*@paramskuId 商品ID*/
publicString test(String skuId) {
decreaseStock("KEY_SKU_"+skuId, skuId);//线程1
new Thread(()->{
decreaseStock("KEY_SKU_"+skuId, skuId);
});//线程2
new Thread(()->{
decreaseStock("KEY_SKU_"+skuId, skuId);
});return "";
}
}