redis实现分布式锁

    使用redis实现一个简单的分布式锁,主要是使用redis的setnx和getset方法进行实现。

加锁:

     1.使用setnx设置值:

            key:为需要加锁的锁名  value 为 当前时间+锁的超时时间

            成功:

                返回true 和锁的超时时间

            失败:

                根据key获取超时时间

                      为空:说明该锁已经释放了,重新获取锁

                      不为空:

                                  判断锁是否已经超时

                                  超时:

                                        使用getset进行获取锁

                                              如果返回的值和上一步获取的锁的超时时间一样说明获取锁,(当不一样时可能会导致将上一个线程设置的锁的超时时间进行修改,应该影响不大。)

                                  没有超时:

                                        说明锁被别的线程持有。

解锁:

     解锁只可解除自己加的锁:

     先获取锁的超时时间

         为空:说明该锁已经不存在了

        不为空:  根据加锁得到的返回值 和解锁得到的时间进行比较,如果一样说明是自己加的锁。

代码:

com.huan.redis.redis_lock.Lock.LockResult ---> 获取锁之后的返回值   用于判断是否获取锁 和 放入锁中的内容

com.huan.redis.redis_lock.Lock                    ---> 锁的接口

com.huan.redis.redis_lock.RedisLock           ---> 锁的具体实现

锁的接口

package com.huan.redis.redis_lock;

/**
 * 锁的接口
 * 
 * @描述
 * @作者 huan
 * @时间 2016年10月30日 - 下午2:31:10
 */
public interface Lock {

	LockResult lock(String lockName);

	/**
	 * 获取锁
	 * 
	 * @param lockName
	 *            需要上那一把锁
	 * @param lockTime
	 *            需要使用所的时间
	 * @param waitTime
	 *            当waitTime这个时间之内还没有获取到锁就退出获取锁
	 */
	LockResult lock(String lockName, long lockTime, long waitTime);

	/**
	 * 释放锁
	 * 
	 * @param lockName
	 */
	void unLock(String lockName, LockResult result);

	static class LockResult {
		private boolean lock;
		private long info;

		public LockResult(boolean lock, long info) {
			super();
			this.lock = lock;
			this.info = info;
		}

		public boolean isLock() {
			return lock;
		}

		public void setLock(boolean lock) {
			this.lock = lock;
		}

		public long getInfo() {
			return info;
		}

		public void setInfo(long info) {
			this.info = info;
		}
	}
}

 锁的具体实现

package com.huan.redis.redis_lock;

import java.text.SimpleDateFormat;
import java.util.Date;

import redis.clients.jedis.Jedis;

/**
 * 使用redis实现分布式锁
 * 
 * @描述
 * @作者 huan
 * @时间 2016年10月30日 - 下午2:39:11
 */
public class RedisLock implements Lock {

	private Jedis jedis;

	public RedisLock(Jedis jedis) {
		this.jedis = jedis;
	}

	@Override
	public LockResult lock(String lockName, long lockTime, long waitTime) {
		long now = System.currentTimeMillis();
		LockResult lockResult = new LockResult(false, 0);
		while (System.currentTimeMillis() - now <= waitTime) { // 重试 直到超时
			long needLockTime = System.currentTimeMillis() + lockTime;
			if (jedis.setnx("lock:" + lockName, String.valueOf(needLockTime)) == 1) { // 获取锁
				System.out.println(Thread.currentThread().getName() + " : 获取锁1.." + new SimpleDateFormat("yyyyMMdd HH:mm:ss").format(new Date()));
				lockResult = new LockResult(true, needLockTime);
				return lockResult;
			}
			String oldTime = jedis.get("lock:" + lockName); // 如果没有获取锁,则获取锁的持有时间
			if (null != oldTime) { // 锁还在
				if (System.currentTimeMillis() - Long.parseLong(oldTime) > 0) { // 锁已经超时
					needLockTime = System.currentTimeMillis() + lockTime; // 计算新的锁超时时间
					String _oldLockTime = jedis.getSet("lock:" + lockName, String.valueOf(needLockTime)); // 设置锁的超时时间
					if (null != oldTime && _oldLockTime != null && oldTime.equals(_oldLockTime)) { // 获取锁
						System.out.println(Thread.currentThread().getName() + " : 获取锁2.." + new SimpleDateFormat("yyyyMMdd HH:mm:ss").format(new Date()));
						lockResult = new LockResult(true, needLockTime);
						return lockResult;
					} else {
						// System.out.println("另外的线程释放锁.");
					}
				}
				// System.out.println(Thread.currentThread().getName() + " : 尝试获取锁..");
			} else { // 另外的线程释放锁,需要重新获取锁
				needLockTime = System.currentTimeMillis() + lockTime; // 计算新的锁超时时间
				if (jedis.setnx("lock:" + lockName, String.valueOf(needLockTime)) == 1) {
					System.out.println(Thread.currentThread().getName() + " : 获取锁3.." + new SimpleDateFormat("yyyyMMdd HH:mm:ss").format(new Date()));
					lockResult = new LockResult(true, needLockTime);
					return lockResult;
				}
			}
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
				Thread.currentThread().interrupt();
			}
		}

		return lockResult;
	}

	@Override
	public void unLock(String lockName, LockResult lockResult) {
		String oldTime = jedis.get("lock:" + lockName);
		if (null != oldTime && lockResult.isLock() && lockResult.getInfo() == Long.parseLong(oldTime)) {
			System.out.println(Thread.currentThread().getName() + " 释放锁.." + new SimpleDateFormat("yyyyMMdd HH:mm:ss").format(new Date()));
			jedis.del("lock:" + lockName);
		} else {
			if (0 == lockResult.getInfo()) {
				System.out.println(Thread.currentThread().getName() + " : 获取锁失败...");
			} else {
				System.out.println(Thread.currentThread().getName() + " 持有的锁由于已经被被的线程修改锁不用次线程进行释放.");
			}
		}
	}

	@Override
	public LockResult lock(String lockName) {
		return lock(lockName, Long.MAX_VALUE, Long.MAX_VALUE);
	}
}

 测试:

posted @ 2016-10-30 17:19  huan1993  阅读(24)  评论(0编辑  收藏  举报