package com.rynk.mugua.trading.biz.commons.lock; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ValueOperations; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import javax.annotation.Resource; import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.TimeUnit; /** * 分布式锁 * * @author ZHANGYUKUN * */ @Component public class DistributedLockHandler { private static final Logger logger = LoggerFactory.getLogger(DistributedLockHandler.class); /** * 最大持有锁的时间(毫秒) */ private final static long LOCK_EXPIRE = 30 * 1000L; /** * 尝试获取锁的时间间隔(毫秒) */ private final static long LOCK_TRY_INTERVAL = 30L; /** * 获取锁最大等待时间( 毫秒 ) */ private final static long LOCK_TRY_TIMEOUT = 20 * 1000L; @Resource// (name = "customRedisTemplate") private RedisTemplate<String, String> template; /** * 尝试获取 分布式锁 * * @param lockKey * 锁名 * @return true 得到了锁 ,false 获取锁失败 */ public boolean tryLock(String lockKey) { return getLock(lockKey, LOCK_TRY_TIMEOUT, LOCK_TRY_INTERVAL, LOCK_EXPIRE); } /** * 尝试获取 分布式锁(不自动释放锁) * * @param lockKey * 锁名 * @return true 得到了锁 ,false 获取锁失败 */ public boolean tryLockNotAutoRelease(String lockKey) { return getLock(lockKey, LOCK_TRY_TIMEOUT, LOCK_TRY_INTERVAL, -1); } /** * 尝试获取 分布式锁 * * @param lockKey * 锁名 * @param timeout * 获取锁最大等待时间 * @return true 得到了锁 ,false 获取锁失败 */ public boolean tryLock(String lockKey, long timeout) { return getLock(lockKey, timeout, LOCK_TRY_INTERVAL, LOCK_EXPIRE); } /** * 尝试获取 分布式锁(不自动释放锁) * * @param lockKey * 锁名 * @param timeout * 获取锁最大等待时间 * @return true 得到了锁 ,false 获取锁失败 */ public boolean tryLockNotAutoRelease(String lockKey, long timeout) { return getLock(lockKey, timeout, LOCK_TRY_INTERVAL, -1); } /** * 尝试获取 分布式锁 * * @param lockKey * 锁名 * @param timeout * 获取锁最大等待时间 * @param tryInterval * 获取锁尝试 时间间隔 * @return true 得到了锁 ,false 获取锁失败 */ public boolean tryLock(String lockKey, long timeout, long tryInterval) { return getLock(lockKey, timeout, tryInterval, LOCK_EXPIRE); } /** * 尝试获取 分布式锁(不释放锁) * * @param lockKey * 锁名 * @param timeout * 获取锁最大等待时间 * @param tryInterval * 获取锁尝试 时间间隔 * @return true 得到了锁 ,false 获取锁失败 */ public boolean tryLockNotAutoRelease(String lockKey, long timeout, long tryInterval) { return getLock(lockKey, timeout, tryInterval, -1); } /** * 尝试获取 分布式锁 * * @param lockKey * 锁名 * @param timeout * 获取锁最大等待时间 * @param tryInterval * 获取锁尝试 时间间隔 * @param lockExpireTime * 锁最大持有时间 * @return true 得到了锁 ,false 获取锁失败 */ public boolean tryLock(String lockKey, long timeout, long tryInterval, long lockExpireTime) { return getLock(lockKey, timeout, tryInterval, lockExpireTime); } /** * 获取分布式锁 * * @param lockKey * 锁名 * @param timeout * 获取锁最大等待时间 * @param tryInterval * 获取锁尝试 时间间隔 * @param lockExpireTime * 锁最大持有时间 * @return true 得到了锁 ,false 获取锁失败 */ private boolean getLock(String lockKey, long timeout, long tryInterval, long lockExpireTime) { try { if (StringUtils.isEmpty(lockKey)) { return false; } long startTime = System.currentTimeMillis(); do { ValueOperations<String, String> ops = template.opsForValue(); SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); if (lockExpireTime > 0) { if (ops.setIfAbsent(lockKey, sd.format(new Date()),lockExpireTime, TimeUnit.MILLISECONDS )) { return true; } }else { if (ops.setIfAbsent(lockKey, sd.format(new Date()) )) { return true; } } Thread.sleep(tryInterval); } while (System.currentTimeMillis() - startTime < timeout); } catch (InterruptedException e) { logger.error(e.getMessage()); return false; } return false; } /** * 释放锁 * * @param lockKey */ public void unLock(String lockKey) { if (!StringUtils.isEmpty(lockKey)) { if( template.hasKey(lockKey) ) { template.delete(lockKey); } } } }
测试代码:启动 100 个线程 并发的 个 a 加1 ,如果 如果 能锁住 ,那么 100 个线程会排队 逐步打印 0 到 99.
@Autowired DistributedLockHandler lock; ExecutorService executorService = Executors.newFixedThreadPool(1000); int a= 0; @PostMapping("/t1") @ApiOperation(value = "t1") public CommonResult<String> t1( BigDecimal scale) { String key = "key1"; for( int i=0;i<100;i++ ) { executorService.execute( ()->{ try { if( lock.tryLock( key ) ) { System.out.println("得到" + a ); a++; } }catch (Exception e) { e.printStackTrace(); }finally { lock.unLock(key); } } ); } a = 0; return CommonResult.getSucceedInstance(); }
结果截图: