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; private org.slf4j.Logger logger = LoggerFactory.getLogger(this.getClass()); /** * * @desc 加鎖 * @param key * @param value * @param timeout 超時時間 * @param autoReleaseTime 自動釋放鎖時間 */ public boolean lock(String key, String value, long timeout, long autoReleaseTime) { 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); } return flag; } /** * * @desc 解鎖 * @param key * @param value */ public void unLock(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); } } /** * 扣減庫存 */ public String 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 ""; } /** * 測試可模擬多個線程扣減庫存 * @param skuId 商品ID */ public String 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 ""; } }