平常的开发中,咱们常常会遇到不一样线程或进程须要互斥访问资源的状况,这时候分布式的锁就是很是有必要的了。分布式锁实现方式能够有不少种:如mysql、redis、zookeeper等。java
这里简单地分享一下基于redis的实现。mysql
这里使用了几个主要的redis命令: set 、get 、del。redis
SET的命令格式:sql
SET key value NX PX milliseconds SET key value NX EX seconds
这里必定要使用NX,由于NX表示只有key不存在时,SET才能成功。dom
从接口上,锁应该分为获取锁和释放锁。分布式
获取锁:经过set命令设置一个key的值,并返回锁的内容。若是没有set成功,即表示已经被其它线程或进程占用,能够继续尝试获取。ui
释放锁:经过del命令将这个key值删除便可,可是为保证释放锁的可靠性须要验证锁的内容。this
下面贴上具体的实现代码,注释也比较清楚,再也不详细描述。线程
package com.zheng.coderepo.redis; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import java.util.UUID; import java.util.concurrent.TimeUnit; /** * redis分布式锁 * Created by zhangchaozheng on 16-7-28. */ public class RedisLock { private final static String UNLOCK_LUA = "" + "if redis.call(\"get\",KEYS[1]) == ARGV[1] " + "then " + " return redis.call(\"del\",KEYS[1]) " + "else " + " return 0 " + "end"; //等待锁时间 private final static long WAIT_LOCK_TIME = 300; private JedisPool jedisPool; public RedisLock(JedisPool jedisPool) { this.jedisPool = jedisPool; } /** * 若是分布式锁不可用, 当前线程将继续请求, 直到锁可用. * * @param lockKey 锁的键值 * @param timeout 超时时间.单位:毫秒. * @return 锁的值. */ public String lock(String lockKey, long timeout) { String lockVal = UUID.randomUUID().toString(); for (; ; ) { if (!tryLock(lockKey, lockVal, timeout)) { try { TimeUnit.MILLISECONDS.sleep(WAIT_LOCK_TIME); } catch (InterruptedException e) { } } else { break; } } return lockVal; } /** * 尝试得到分布式锁, 若是锁可用, 返回true * * @param lockKey 锁的键值 * @param value 锁的值,推荐使用随机字符. * @param timeout 超时时间.单位:毫秒. * @return true/false */ public boolean tryLock(String lockKey, String value, long timeout) { Jedis jedis = jedisPool.getResource(); try { Object result = jedis.set(lockKey, value, "NX", "PX", timeout); return "OK".equalsIgnoreCase(result + ""); } finally { quietlyCloseJedis(jedis); } } /** * 释放锁. * * @param lockKey 锁的键值 * @param value 锁的值.必需要和上锁的值一致. */ public void unlock(String lockKey, String value) { Jedis jedis = jedisPool.getResource(); try { jedis.eval(UNLOCK_LUA, 1, lockKey, value); } finally { quietlyCloseJedis(jedis); } } /** * 关闭redis链接。jedis 3.0开始,官方抛弃了原来的returnResource和returnBrokenResource。 * * @param jedis */ private void quietlyCloseJedis(Jedis jedis) { if (jedis != null) { jedis.close(); } } }