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

 

 

结果截图:  

 

 

 

 

 

 

posted on 2019-03-26 10:31  zhangyukun  阅读(145)  评论(0编辑  收藏  举报

导航