您的位置:首页 > 数据库 > Redis

redis分布式锁实现控制并发

2017-06-30 17:07 232 查看
最近项目有一个关于征信协议生成pdf,要求客户签订的第一份协议生成pdf,由于是服务器集群,所以要用到分布式锁的概念。

写完后,写了个例子总结了下,直接上例子

import java.util.HashSet;

import java.util.Set;

import java.util.concurrent.TimeUnit;

import org.apache.commons.lang.math.RandomUtils;

import org.springframework.data.redis.core.TimeoutUtils;

import redis.clients.jedis.HostAndPort;

import redis.clients.jedis.JedisCluster;

public class Test {

    

    static Set<HostAndPort> haps_dest_dev = new HashSet<HostAndPort>();

    static JedisCluster jedisCluster;

    static {

        haps_dest_dev.add(new HostAndPort("172.29.0.97", 6379));

        haps_dest_dev.add(new HostAndPort("172.29.0.97", 6389));

        haps_dest_dev.add(new HostAndPort("172.29.0.97", 6399));

        haps_dest_dev.add(new HostAndPort("172.29.0.98", 6379));

        haps_dest_dev.add(new HostAndPort("172.29.0.98", 6389));

        haps_dest_dev.add(new HostAndPort("172.29.0.98", 6399));

        jedisCluster = new JedisCluster(haps_dest_dev);

    }

    

    /** 毫秒与毫微秒的换算单位 1毫秒 = 1000000毫微秒 */

    public static final long MILLI_NANO_CONVERSION = 1000 * 1000L;

    /** 默认超时时间(毫秒) */

    public static final long DEFAULT_TIME_OUT = 1000;

    

//    private volatile boolean locked = false;

    

    /** 

     * 获取锁 

     * @param timeout     获取锁的等待时间  毫秒

     * @param expireSecs  锁的有效时间,必须大于0 毫秒

     * @return 

     */  

    private boolean lock(String lockKey, long timeout, int expireSecs) throws InterruptedException {  

        if (expireSecs <= 0) {  

            throw new IllegalArgumentException("Param expireSecs must lager than zero.");  

        }  

        long nano = System.nanoTime();  

        timeout *= MILLI_NANO_CONVERSION;  

        try {  

            while ((System.nanoTime() - nano) < timeout) {  

            long expires = System.currentTimeMillis() + expireSecs + 1;

            // 5秒之后锁到期

                String expiresStr = String.valueOf(expires); //锁到期时间

                // 获取到锁

                if (jedisCluster.setnx(lockKey, String.valueOf(expiresStr)) == 1) {

                // lock acquired

//                 locked = true;

                jedisCluster.expire(lockKey, (int) TimeoutUtils.toSeconds(expireSecs, TimeUnit.MILLISECONDS)); 

                    return true;  

                }  

                // 没有获取到锁

                String currentValueStr = jedisCluster.get(lockKey); 

                // expireMsecs(5秒)锁的有效期内无法进入if判断,如果锁超时了

                if (currentValueStr != null && Long.parseLong(currentValueStr) < System.currentTimeMillis()) {

                //判断是否为空,不为空的情况下,如果被其他线程设置了值,则第二个条件判断是过不去的

                    // lock is expired

                // 如果锁超时重新设置

                    String oldValueStr = jedisCluster.getSet(lockKey, expiresStr);

                    //获取上一个锁到期时间,并设置现在的锁到期时间,

                    //只有一个线程才能获取上一个线上的设置时间,因为jedis.getSet是同步的

                    // 值相同说明是同一个线程的操作,获取锁成功

                    if (oldValueStr != null && oldValueStr.equals(currentValueStr)) {

                    //防止误删(覆盖,因为key是相同的)了他人的锁——这里达不到效果,这里值会被覆盖,但是因为什么相差了很少的时间,所以可以接受

                    //如过这个时候,多个线程恰好都到了这里,但是只有一个线程的设置值和当前值相同,他才有权利获取锁

                        // lock acquired
//                     locked = true;

                    jedisCluster.expire(lockKey, (int) TimeoutUtils.toSeconds(expireSecs, TimeUnit.MILLISECONDS));

                        return true;

                    } else {

                        // 被其他线程抢先获取锁

//                        locked = false;

                    }

                }

               // 锁没有超时,继续等待

            }  

            

            Thread.sleep(3, RandomUtils.nextInt(500));  

        } catch (Exception e) {  

            throw new RuntimeException("Locking error", e);  

        } 

        return false;  

    }

    

    

    /**

     * 释放锁

     */

    public void releaseLock(String lockKey){

        try {

            long current = System.currentTimeMillis();  

            // 避免删除非自己获取得到的锁

            if (current < Long.valueOf(jedisCluster.get(lockKey)))

            jedisCluster.del(lockKey);

//                locked = false;

        } catch (Exception e) {

            e.printStackTrace();

        }

    }

    public static void main(String[] args) {

    Test t = new Test();

        try {

        if (t.lock("lock:aa", DEFAULT_TIME_OUT, 5000)) {

        System.out.println("获取锁");

        } else {

        System.out.println("未获取锁");

        }

        } catch (Exception e1) {

            e1.printStackTrace();

        }

    }

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: