• 基于redis的 分布式锁 Java实现


    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();
    	}
    

    结果截图:  

     

     

  • 相关阅读:
    商务通服务器版LR_Data目录下相关配置文件
    Python入门神图
    你不知道的JavaScript-2.词法作用域
    你不知道的JavaScript-1.作用域是什么
    linux服务器对外打包处理
    C# Form 关闭按钮灰化
    Spread常用属性
    Spread 常用属性
    C#打开关闭窗体事件顺序
    sqlserver如何使用日期计算
  • 原文地址:https://www.cnblogs.com/cxygg/p/10598635.html
Copyright © 2020-2023  润新知