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