zoukankan      html  css  js  c++  java
  • 分布式锁 基于Redis

    分布式锁的实现(基于Redis)

    参考: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的安装,请参考redis安装

    2.redssion库

    redssion的库添加的pom文件中去。

    <dependency>
       <groupId>org.redisson</groupId>
       <artifactId>redisson</artifactId>
       <version>2.1.0</version>
    </dependency>

    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.参考

    redisson

    方式二: 自定义代码实现 



    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;
    }
    }
    }
  • 相关阅读:
    最大堆的实现
    更新Android SDK Manager Mac下修改hosts
    快速排序
    含有通配符的字符串匹配(递归)
    geopandas安装问题记录:ImportError,DLL load failedwindows10
    silveright 5.0 搜索代码生成系统
    Insert xml to DB Column
    Enter/Esc Hot Key Silverlight
    Silverlight 页面保存为html出现乱码的问题
    Use dynamic SQL to fix openrowset parameter and Insert xml files into database under given folder
  • 原文地址:https://www.cnblogs.com/xmanblue/p/5301858.html
Copyright © 2011-2022 走看看