Redis分布式锁java实现

1、定义redis实现分布式锁的接口

package com.iol.common.util.concurrent.locks;

import java.io.Serializable;

/**
 * Description: 定义redis实现分布式锁的算法<br />
 * This program is protected by copyright IOL_SMALL_TAIL.<br />
 * Program Name: IOL_SMALL_TAIL<br />
 * Date: 2015年11月8日
 *
 * @author 王鑫
 * @version 1.0
 */
public interface IRedisLockArithmetic extends Serializable {
	/**
	 * 加锁算法<br />
	 * @param key
	 * @return
	 */
	public boolean lock(String key);
	
	/**
	 * 解锁算法<br />
	 * @param key
	 * @return
	 */
	public boolean unLock(String key);
}

2、redis分布式锁基础算法实现

package com.iol.common.util.concurrent.locks.arithmetic;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.iol.common.util.concurrent.locks.IRedisComponent;
import com.iol.common.util.concurrent.locks.IRedisLockArithmetic;

/**
 * Description: redis分布式锁基础算法实现<br />
 * This program is protected by copyright IOL_SMALL_TAIL.<br />
 * Program Name: IOL_SMALL_TAIL<br />
 * Date: 2015年11月9日
 *
 * @author 王鑫
 * @version 1.0
 */
public class RedisLockBaseArithmetic implements IRedisLockArithmetic {
	/**
	 *serialVersionUID
	 */
	private static final long serialVersionUID = -8333946071502606883L;
	
	private Logger logger = LoggerFactory.getLogger(RedisLockBaseArithmetic.class);

	/**
	 * redis操作方法
	 */
	private IRedisComponent redisComp;
	
	/**
	 * 超时时间,以毫秒为单位<br />
	 * 默认为5分钟
	 */
	private long overtime = 5 * 60 * 1000L;
	
	/**
	 * 休眠时长,以毫秒为单位<br />
	 * 默认为100毫秒
	 */
	private long sleeptime = 100L;
	
	/**
	 * 当前时间
	 */
	private long currentLockTime;
	
	/**
	 * @param redisComp the redisComp to set
	 */
	public void setRedisComp(IRedisComponent redisComp) {
		this.redisComp = redisComp;
	}

	/**
	 * @param overtime the overtime to set
	 */
	public void setOvertime(long overtime) {
		this.overtime = overtime;
	}

	/**
	 * @param sleeptime the sleeptime to set
	 */
	public void setSleeptime(long sleeptime) {
		this.sleeptime = sleeptime;
	}

	/* (non-Javadoc)
	 * @see com.iol.common.util.concurrent.locks.IRedisLockArithmetic#lock(java.lang.String, java.lang.Long)
	 */
	@Override
	public boolean lock(String key) {
		while(true) {
			// 当前加锁时间
			currentLockTime = System.currentTimeMillis();
			
			if(redisComp.setIfAbsent(key, currentLockTime)) {
				// 获取锁成功
				logger.debug("直接获取锁{key: {}, currentLockTime: {}}", key, currentLockTime);
				return true;
			} else {
				//其他线程占用了锁
				logger.debug("检测到锁被占用{key: {}, currentLockTime: {}}", key, currentLockTime);
				Long otherLockTime = redisComp.get(key);
				if(otherLockTime == null) {
					// 其他系统释放了锁
					// 立刻重新尝试加锁
					logger.debug("检测到锁被释放{key: {}, currentLockTime: {}}", key, currentLockTime);
					continue;
				} else {
					if(currentLockTime - otherLockTime >= overtime) {
						//锁超时
						//尝试更新锁
						logger.debug("检测到锁超时{key: {}, currentLockTime: {}, otherLockTime: {}}", key, currentLockTime, otherLockTime);
						Long otherLockTime2 = redisComp.getAndSet(key, currentLockTime);
						if(otherLockTime2 == null || otherLockTime.equals(otherLockTime2)) {
							logger.debug("获取到超时锁{key: {}, currentLockTime: {}, otherLockTime: {}, otherLockTime2: {}}", key, currentLockTime, otherLockTime, otherLockTime2);
							return true;
						} else {
							sleep();
							//重新尝试加锁
							logger.debug("重新尝试加锁{key: {}, currentLockTime: {}}", key, currentLockTime);
							continue;
						}
					} else {
						//锁未超时
						sleep();
						//重新尝试加锁
						logger.debug("重新尝试加锁{key: {}, currentLockTime: {}}", key, currentLockTime);
						continue;
					}
				}
			}
		}
	}

	/* (non-Javadoc)
	 * @see com.iol.common.util.concurrent.locks.IRedisLockArithmetic#unLock(java.lang.String)
	 */
	@Override
	public boolean unLock(String key) {
		logger.debug("解锁{key: {}}", key);
		redisComp.delete(key);
		return true;
	}
	
	/**
	 * 休眠<br />
	 * @param sleeptime
	 */
	private void sleep() {
		try {
			Thread.sleep(sleeptime);
		} catch (InterruptedException e) {
			throw new LockException("线程异常中断", e);
		}
	}
}

3、定义实际操作Redis的组件所使用的方法接口

package com.iol.common.util.concurrent.locks;

import java.io.Serializable;

/**
 * Description: 定义实际操作Redis的组件所使用的方法<br />
 * This program is protected by copyright IOL_SMALL_TAIL.<br />
 * Program Name: IOL_SMALL_TAIL<br />
 * Date: 2015年11月8日
 *
 * @author 王鑫
 * @version 1.0
 */
public interface IRedisComponent extends Serializable {
	/**
	 * 执行redis的SETNX命令
	 * @param key
	 * @param timeMillisecond
	 * @return
	 */
	public Boolean setIfAbsent(String key, Long timeMillisecond);
	
	/**
	 * 执行redis的GET命令<br />
	 * @param key
	 * @return
	 */
	public Long get(String key);
	
	/**
	 * 执行redis的GETSET命令<br />
	 * @param key
	 * @param timeMillisecond
	 * @return
	 */
	public Long getAndSet(String key, Long timeMillisecond);
	
	/**
	 * 执行redis的DEL命令<br />
	 * @param key
	 * @return
	 */
	public void delete(String key);
}

4、spring实现的redis组件的方法

package com.iol.common.util.concurrent.locks.component;

import org.springframework.data.redis.core.RedisTemplate;

import com.iol.common.util.concurrent.locks.IRedisComponent;

/**
 * Description: spring实现的redis组建<br />
 * This program is protected by copyright IOL_SMALL_TAIL.<br />
 * Program Name: IOL_SMALL_TAIL<br />
 * Date: 2015年11月10日
 *
 * @author 王鑫
 * @version 1.0
 */
public class SpringRedisComponent implements IRedisComponent {
	/**
	 *serialVersionUID
	 */
	private static final long serialVersionUID = 3673851740133937797L;
	
	private RedisTemplate<String, Long> redisTemplate;
	
	/**
	 * @param redisTemplate the redisTemplate to set
	 */
	public void setRedisTemplate(RedisTemplate<String, Long> redisTemplate) {
		this.redisTemplate = redisTemplate;
	}

	/* (non-Javadoc)
	 * @see com.iol.common.util.concurrent.locks.IRedisComponent#setIfAbsent(java.lang.String, java.lang.Long)
	 */
	@Override
	public Boolean setIfAbsent(String key, Long timeMillisecond) {
		return redisTemplate.opsForValue().setIfAbsent(key, timeMillisecond);
	}

	/* (non-Javadoc)
	 * @see com.iol.common.util.concurrent.locks.IRedisComponent#get(java.lang.String)
	 */
	@Override
	public Long get(String key) {
		return redisTemplate.opsForValue().get(key);
	}

	/* (non-Javadoc)
	 * @see com.iol.common.util.concurrent.locks.IRedisComponent#getAndSet(java.lang.String, java.lang.Long)
	 */
	@Override
	public Long getAndSet(String key, Long timeMillisecond) {
		return redisTemplate.opsForValue().getAndSet(key, timeMillisecond);
	}

	/* (non-Javadoc)
	 * @see com.iol.common.util.concurrent.locks.IRedisComponent#delete(java.lang.String)
	 */
	@Override
	public void delete(String key) {
		redisTemplate.delete(key);
	}
}

5、创建RedisLock的工厂方法定义

package com.iol.common.util.concurrent.locks;

/**
 * Description: 创建RedisLock的工厂方法定义<br />
 * This program is protected by copyright IOL_SMALL_TAIL.<br />
 * Program Name: IOL_SMALL_TAIL<br />
 * Date: 2015年11月10日
 *
 * @author 王鑫
 * @version 1.0
 */
public interface IRedisLockFactoryBean {
	/**
	 * 工厂方法<br />
	 * @param key
	 * 
	 * @return
	 */
	public RedisLock createLock(String key);
}

6、简单的RedisLock工厂类实现

package com.iol.common.util.concurrent.locks;

import org.apache.commons.lang3.StringUtils;

import com.iol.common.util.concurrent.locks.arithmetic.RedisLockBaseArithmetic;

/**
 * Description: 简单的RedisLock工厂类<br />
 * This program is protected by copyright IOL_SMALL_TAIL.<br />
 * Program Name: IOL_SMALL_TAIL<br />
 * Date: 2015年11月10日
 *
 * @author 王鑫
 * @version 1.0
 */
public class SimpleRedisLockFactoryBean implements IRedisLockFactoryBean {
	/**
	 * 操作redis的
	 */
	private IRedisComponent redisComponent;
	
	/**
	 * 超时时间
	 */
	private String overtime;
	
	/**
	 * 休眠时间
	 */
	private String sleeptime;
	
	/**
	 * @param redisComponent the redisComponent to set
	 */
	public void setRedisComponent(IRedisComponent redisComponent) {
		this.redisComponent = redisComponent;
	}

	/**
	 * @param overtime the overtime to set
	 */
	public void setOvertime(String overtime) {
		this.overtime = overtime;
	}

	/**
	 * @param sleeptime the sleeptime to set
	 */
	public void setSleeptime(String sleeptime) {
		this.sleeptime = sleeptime;
	}

	/* (non-Javadoc)
	 * @see com.iol.common.util.concurrent.locks.IRedisLockFactoryBean#createLock(java.lang.String)
	 */
	@Override
	public RedisLock createLock(String key) {
		RedisLockBaseArithmetic arithmetic = new RedisLockBaseArithmetic();
		if(redisComponent != null) {
			arithmetic.setRedisComp(redisComponent);
		} else {
			throw new RedisLockCreateException("redisComponent未初始化");
		}
		if(StringUtils.isNotEmpty(overtime)) {
			arithmetic.setOvertime(Long.parseLong(overtime));
		}
		if(StringUtils.isNotEmpty(sleeptime)) {
			arithmetic.setSleeptime(Long.parseLong(sleeptime));
		}
		
		RedisLock lock = new RedisLock(key, arithmetic);
		return lock;
	}
}

7、简单的使用spring-redis实现的分布式锁

package com.iol.common.util.concurrent.locks;

import java.io.Serializable;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

/**
 * Description: 简单的使用spring-redis实现的分布式锁<br />
 * This program is protected by copyright simon-common.<br />
 * Program Name: simon-common<br />
 * Date: 2015年9月8日
 *
 * @author 王鑫
 * @version 1.0
 */
public class RedisLock implements Lock, Serializable {
	/**
	 *serialVersionUID
	 */
	private static final long serialVersionUID = 6278513934629913285L;

	private IRedisLockArithmetic arithmetic;
	
	private String key;
	
	public RedisLock(String key, IRedisLockArithmetic arithmetic) {
		this.key = key;
		this.arithmetic = arithmetic;
	}
	
	/* (non-Javadoc)
	 * @see java.util.concurrent.locks.Lock#lock()
	 */
	@Override
	public synchronized void lock() {
		arithmetic.lock(key);
	}
	
	/* (non-Javadoc)
	 * @see java.util.concurrent.locks.Lock#unlock()
	 */
	@Override
	public synchronized void unlock() {
		arithmetic.unLock(key);
	}

	/* (non-Javadoc)
	 * @see java.util.concurrent.locks.Lock#lockInterruptibly()
	 */
	@Override
	public void lockInterruptibly() throws InterruptedException {
		throw new UnsupportedOperationException("方法未实现");
	}

	/* (non-Javadoc)
	 * @see java.util.concurrent.locks.Lock#tryLock()
	 */
	@Override
	public boolean tryLock() {
		throw new UnsupportedOperationException("方法未实现");
	}

	/* (non-Javadoc)
	 * @see java.util.concurrent.locks.Lock#tryLock(long, java.util.concurrent.TimeUnit)
	 */
	@Override
	public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
		throw new UnsupportedOperationException("方法未实现");
	}

	/* (non-Javadoc)
	 * @see java.util.concurrent.locks.Lock#newCondition()
	 */
	@Override
	public Condition newCondition() {
		throw new UnsupportedOperationException("方法未实现");
	}
}

8、定义分布式锁异常

package com.iol.common.util.concurrent.locks;

/**
 * Description: 分布式锁异常<br />
 * This program is protected by copyright IOL_SMALL_TAIL.<br />
 * Program Name: IOL_SMALL_TAIL<br />
 * Date: 2015年11月9日
 *
 * @author 王鑫
 * @version 1.0
 */
public class RedisLockException extends RuntimeException {
	/**
	 *serialVersionUID
	 */
	private static final long serialVersionUID = 5781958965016402002L;

	/**
	 * 创建RedisLockException
	 * @param msg
	 */
	public RedisLockException(String msg) {
		super(msg);
	}
	
	/**
	 * 创建RedisLockException
	 * @param msg
	 * @param cause
	 */
	public RedisLockException(String msg, Throwable cause) {
		super(msg, cause);
	}
}

9、分布式锁异常实现

package com.iol.common.util.concurrent.locks;

/**
 * Description: TODO<br />
 * This program is protected by copyright IOL_SMALL_TAIL.<br />
 * Program Name: IOL_SMALL_TAIL<br />
 * Date: 2015年11月10日
 *
 * @author 王鑫
 * @version 1.0
 */
public class RedisLockCreateException extends RedisLockException {
	/**
	 *serialVersionUID
	 */
	private static final long serialVersionUID = -3294103499200541403L;
	
	private static final String baseMsg = "RedisLock创建异常: %s";
	
	/**
	 * 创建RedisLockCreateException
	 */
	public RedisLockCreateException(String msg) {
		super(String.format(baseMsg, msg));
	}
}
    原文作者:java锁
    原文地址: https://blog.csdn.net/junlong750/article/details/51783111
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞