参考:http://www.jb51.net/article/75439.htm
http://www.linuxidc.com/Linux/2015-01/111827.htm
http://www.tuicool.com/articles/6juqmm7
方式一: 基于第三方类库 redssion
1.安装redis
安装redssion的锁服务队redis的版本有要求,要求必须高于2.6版本。关于redis的安装,请参考。
2.redssion库
redssion的库添加的pom文件中去。
org.redisson redisson 2.1.0
3.测试例子
Config config = new Config(); config.useSingleServer().setAddress("ipaddress:6379"); Redisson redisson = Redisson.create(config); for(int i=0;i<5;i++){ RLock lock = redisson.getLock("testLock"); lock.lock(10, TimeUnit.SECONDS);//10s超时 logger.info("the lock client id is client{}",i); Thread.sleep(1000); logger.info("client{} unlock",i); lock.unlock(); }
4.参考
方式二: 自定义代码实现
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import redis.clients.jedis.Jedis; /** * redis实现的分布式锁 */ public final class Lock { private static final String LOCK = "redis:lock:%s"; private static final int EXPIRE = 20 * 60;//20分钟 private static final Logger logger = LoggerFactory.getLogger(Lock.class); private Lock() { } public static Lock getLock() { return new Lock(); } /** * 获得锁,超时退出 * @param id * @param timeout 超时时间(ms) * @return */ public boolean lock(String id, int timeout) { //这里的Jedis实际上是个代理。代理类JedisCallback,JedisFactoryBean Jedis jedisProxy = JedisProxy.create(); long lock = 0; long start = System.currentTimeMillis(); while (lock != 1) { long now = System.currentTimeMillis(); //判断超时 if (timeout > 0 && now > start + timeout) { return false; } long timestamp = now + EXPIRE * 1000 + 1; try { String key = String.format(LOCK, id); lock = jedisProxy.setnx(key, String.valueOf(timestamp)); if (lock == 1) { logger.info("设置redis锁key成功,lock key=" + key); jedisProxy.expire(key, EXPIRE); logger.info("设置redis锁key过期时间成功,lock key=" + key); } else { String s = jedisProxy.get(key); Long lastLockTime = Long.parseLong(s); //一个项目部署多个服务,锁可能已经被相同定时任务的其他进程获得,则直接返回false if (jedisProxy.ttl(key)!=-1&&lastLockTime > System.currentTimeMillis()){ logger.info("redis锁已经被其他服务获得,lock key=" + key); return false; } /** * 如果上次锁定的时间已经过期,则清除key锁,以便定时任务能够启动 * 造成未能释放的原因主要是jedis.expire(key, EXPIRE);失败 * 或者是获取锁之后,由于程序错误或网络错误,unlock未被成功调用 */ if (jedisProxy.ttl(key)==-1||lastLockTime < System.currentTimeMillis()) { jedisProxy.del(key); continue; } // this.wait(100); Thread.sleep(100); } } catch (Exception e) { logger.error("从redis获取定时任务锁错误,key="+String.format(LOCK, id), e); return false; } } return true; } /** * 释放锁 * @param id */ public void unLock(String id) { //这里的Jedis实际上是个代理。代理类JedisCallback,JedisFactoryBean Jedis jedisProxy = JedisProxy.create(); String key = String.format(LOCK, id); jedisProxy.del(key); } }
JedisProxy类
/** * Jedis代理 */ @Component public class JedisProxy implements ApplicationContextAware { private static volatile ApplicationContext ac; /** * 创建Jedis 代理 * * @return */ public static Jedis create() { return ac.getBean(Jedis.class); } @Override public void setApplicationContext(ApplicationContext applicationContext) { if (ac != null) { return; } synchronized (JedisProxy.class) { if (ac != null) { return; } ac = applicationContext; } } }