分佈式redis鎖的實現原理

/** 
 * Project Name:demo-project-generator 
 * File Name:RedisLockBase.java 
 * Package Name:com.gomeplus.market 
 * Date:2017年8月7日上午10:16:23 
 * Copyright (c) 2017, suchao@gomeplus.com All Rights Reserved. 
 * 
*/  

package cn.com.gome.game.rocket.client.base;

import java.util.Date;

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

import redis.Gcache;

/** 
 * ClassName:RedisLockBase <br/> 
 * Function: TODO ADD FUNCTION. <br/> 
 * Reason:   TODO ADD REASON. <br/> 
 * Date:     2017年8月7日 上午10:16:23 <br/> 
 * @author   suchao 
 * @version   
 * @since    JDK 1.8
 * @see       
 */
public abstract class RedisLockBase {
	
	/**
	 * 日誌組件
	 */
	private static final Logger logger = LoggerFactory.getLogger(RedisLockBase.class);
	
	/**
	 * 等待超時時間
	 */
	private long timeout = 12000L;
	
	/**
	 * 等待線程休眠時間
	 */
	private long threadSleep = 20L; 
	
	/**
	 * 鎖的有效時間
	 */
	private long expire = 8000L;
	
	private Gcache cache = null;
	
	/**
	 * 放開獲取redis測權限
	* @Title: getCache  
	* @Description: TODO
	* @param @return
	* @return Gcache
	* @throws
	 */
	public Gcache getCache() {
		return this.cache;
	}
	
	private String timeLock = "";
	
	/**
	 * 
	* <p>Title: </p>  
	* <p>Description: </p>  
	* @param cache
	* @param timeLock
	 */
	public RedisLockBase(Gcache cache,String timeLock) {
		this.cache = cache;
		this.timeLock = timeLock;
		logger.debug("執行默認配置信息,lock:{},鎖保持時間:{},獲取鎖的等待時間:{},獲取等待休眠時間:{}",timeLock,String.valueOf(expire),String.valueOf(timeout),String.valueOf(threadSleep));
	}
	
	/**
	 * 
	* <p>Title: </p>  
	* <p>Description: </p>  
	* @param cache
	* @param timeLock
	* @param timeout
	* @param threadSleep
	* @param expire
	 */
	public RedisLockBase(Gcache cache,String timeLock,long timeout,long threadSleep,long expire) {
		this.cache = cache;
		this.timeLock = timeLock;
		this.timeout = timeout;
		this.threadSleep = threadSleep;
		this.expire = expire;
		logger.debug("執行默認配置信息,lock:{},鎖保持時間:{},獲取鎖的等待時間:{},獲取等待休眠時間:{}",timeLock,String.valueOf(expire),String.valueOf(timeout),String.valueOf(threadSleep));
	}
	
	
	/**
	 * 執行加鎖事件
	* @Title: excuteTask  
	* @Description: TODO
	* @param @param cache
	* @param @param timeLock
	* @param @throws InterruptedException
	* @return void
	* @throws
	 */
	public void excuteTask() throws InterruptedException {
		logger.info("執行鎖定任務的緩存信息,lock:{},開始執行",timeLock);
		//執行
		GOROOT:for(;true;){
			//獲取鎖
			String locktime = cache.get(timeLock);
			if(locktime==null || locktime.equals("")) {
				logger.debug("執行鎖定任務的緩存信息,lock:{},獲取redis鎖爲空,進行加鎖。",timeLock);
				//設置本身的鎖時間
				long lockSelf = new Date().getTime() + expire;
				//設置鎖
				Long lg = cache.setnx(timeLock , String.valueOf(lockSelf));
				if(lg.longValue()>0) {
					//成功
					logger.debug("執行鎖定任務的緩存信息,lock:{},獲取redis鎖成功,setnx返回結果:{}",timeLock,Long.toString(lg));
					//操做數據
					funAction();
					//獲取時間
					String time = cache.get(timeLock);
					long nowTime = new Date().getTime();
					if(time!= null && !time.equals("") && new Long(time).longValue()> nowTime &&  String.valueOf(lockSelf).equals(time)) {
						//釋放鎖--會把別人的鎖刪除掉
						cache.expire(timeLock, -1);
						logger.debug("執行鎖定任務的緩存信息,lock:{},獲取redis鎖成功,鎖時間:{},當前時間:{},清除當前鎖的LOCKKEY",timeLock,time,Long.toString(nowTime));
					}
					logger.debug("執行鎖定任務的緩存信息,lock:{},獲取redis鎖成功,鎖時間:{},當前時間:{}",timeLock,time,Long.toString(nowTime));
				}else {
					long timeouta = 0L;
					do {
						timeouta += threadSleep;
						
						//獲取時間
						String time = cache.get(timeLock);
						long nowTime = new Date().getTime();
						if(time==null || time.equals("") || new Long(time).longValue() < nowTime) {
							//超出了緩存時間
							//釋放鎖
							cache.expire(timeLock, -1);
							logger.debug("執行鎖定任務的緩存信息,lock:{},獲取redis鎖失敗,等待鎖釋放超時-清除鎖,鎖時間:{},當前時間:{}。",timeLock,time,Long.toString(nowTime));
							continue GOROOT;
						}
						Thread.sleep(threadSleep);
					}while(timeouta<timeout);
					
					logger.debug("執行鎖定任務的緩存信息,lock:{},獲取redis鎖失敗,等待鎖超時,執行超時事件。",timeLock);
					//等待超時
					funTimeout();
				}
				
			}else {
				//鎖存在
				logger.debug("執行鎖定任務的緩存信息,lock:{},獲取redis鎖存在,等待鎖釋放。",timeLock);
				long timeouta = 0L;
				do {
					timeouta += threadSleep;
					//獲取時間
					String time = cache.get(timeLock);
					long nowTime = new Date().getTime();
					if(time==null || time.equals("") || new Long(time).longValue() < nowTime) {
						//超出了緩存時間
						logger.debug("執行鎖定任務的緩存信息,lock:{},redis鎖存在-等待鎖釋放超時-清除鎖,鎖時間:{},當前時間:{}",timeLock,time,Long.toString(nowTime));
						//釋放鎖
						cache.expire(timeLock, -1);
						continue GOROOT;
					}
					Thread.sleep(threadSleep);
				}while(timeouta<timeout);
				
				logger.debug("執行鎖定任務的緩存信息,lock:{},獲取redis鎖失敗,等待鎖超時,執行超時事件。",timeLock);
				//等待超時
				funTimeout();
			}
			//跳出整個循環
			break;
		}
		logger.info("執行鎖定任務的緩存信息,lock:{},執行結束。",timeLock);
	}

	
	/**
	 * 超時方法
	* @Title: funTimeout  
	* @Description: TODO
	* @param 
	* @return void
	* @throws
	 */
	protected abstract void funTimeout();
	
	/**
	 * 鎖定處理事件
	* @Title: funAction  
	* @Description: TODO
	* @param 
	* @return void
	* @throws
	 */
	protected abstract void funAction();
	
}
相關文章
相關標籤/搜索