redis缓存实战探究专题

Jedis实现分布式锁与Lua脚本的实现

2019-10-29  本文已影响0人  先生zeng

本篇文章主要讲解如何使用Jedis实现一个简略的分布式锁的,想了解分布式锁相关的内容可以看我这篇文章讲解的:
https://www.jianshu.com/p/b3f95f2d146e

下面直接撸代码:

首先需要一个连接redis的初始化类

package com.zxy.test.jedis.slock;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import java.util.HashMap;

/**
 * @description:...
 * @author xinyao.zeng
 * @date 2019/10/28
 * @version  1.0
 */
public class JedisConnectionUtils {

//    HashMap
    private static JedisPool pool = null;

    static {
        JedisPoolConfig poolConfig = new JedisPoolConfig();

        poolConfig.setMaxTotal(1000);


      //  pool = new JedisPool(poolConfig,"47.74.144.61",6379,500000);
        pool = new JedisPool(poolConfig,"192.168.88.139",6379);

    }

    public static Jedis getJedis(){
        return pool.getResource();
    }
}

一个获取锁和释放锁的工具类

package com.zxy.test.jedis.slock;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;
import java.util.UUID;

/**
 * @description:...
 * @author xinyao.zeng
 * @date 2019/10/28
 * @version  1.0
 */
public class DistributeLock {

    //获得锁

    public String acquireLock(String lockName,long acquireTimeout,long lockTimeout) {

        String identify = UUID.randomUUID().toString();
        String lockKey = "lock:" + lockName;
        int locExpire = (int) (lockTimeout / 1000);
        Jedis jedis = null;
        try{
           jedis = JedisConnectionUtils.getJedis();

            long end = System.currentTimeMillis() + acquireTimeout;
            while (System.currentTimeMillis() < end) {

                //设置成功,代表获取锁成功
                if (jedis.setnx(lockKey, identify) == 1) {
                    jedis.expire(lockKey, locExpire);  //设置超时时间
                    return identify;
                }

                if (jedis.ttl(lockKey) == -1) {
                    jedis.expire(lockKey, locExpire);
                }

                try {
                    //等待片刻进行获取锁的重试
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }finally{
            jedis.close();
        }
        return null;
    }

    //释放锁
    public boolean releaseLock(String lockName,String identifier){
        System.out.println(lockName+"开始释放锁:"+identifier);
        String lockKey = "lock:"+lockName;
        Jedis jedis = null;
        boolean isRelease = false;

        try {
            jedis = JedisConnectionUtils.getJedis();
            while (true) {
                //监控,保证释放锁,不会被打断
                jedis.watch(lockKey);
                //判断是否为同一把锁
                if (identifier.equals(jedis.get(lockKey))) {
                    //事务删除锁
                    Transaction transaction = jedis.multi();

                    transaction.del(lockKey);

                    if (transaction.exec().isEmpty()) {
                        continue;
                    }
                    //认为锁释放成功
                    isRelease = true;

                }
                //TODO 异常
                jedis.unwatch();
                break;
            }

        }finally {
            jedis.close();
        }
        return isRelease;
    }
}

测试类如下:

public class Test extends Thread {

    @Override
    public void run() {
        while(true) {
            DistributeLock distributeLock = new DistributeLock();
            String lock = distributeLock.acquireLock("updateLock", 2000, 5000);
            if (lock != null) {
                System.out.println(Thread.currentThread().getName() + "成功获得锁");
                try {
                    Thread.sleep(1000);

                    boolean updateLock = distributeLock.releaseLock("updateLock", lock);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                break;
            }
        }
    }

    public static void main(String[] args) {

        Test test = new Test();
        CountDownLatch countDownLatch = new CountDownLatch(1);

      /*  try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }*/
        for(int i=0;i<10;i++){
            new Thread(test,"tName"+i).start();
        }
//        countDownLatch.countDown();

    }
}

测试结果:


lua脚本的使用

在DistributeLock 类中添加该方法,在测试类中使用该方法获取锁。

 public boolean releaseLockWithLua(String lockName,String identifier){
        System.out.println(lockName+"开始释放锁:"+identifier);

        Jedis jedis=JedisConnectionUtils.getJedis();
        String lockKey="lock:"+lockName;

        String lua="if redis.call(\"get\",KEYS[1])==ARGV[1] then " +
                "return redis.call(\"del\",KEYS[1]) " +
                "else return 0 end";
        Long rs=(Long) jedis.eval(lua,1,new String[]{lockKey,identifier});
        if(rs.intValue()>0){
            return true;
        }
        return false;

    }

测试类

public class UnitTest extends Thread{

    @Override
    public void run() {
        while(true){
            DistributedLock distributedLock=new DistributedLock();
            String rs=distributedLock.acquireLock("updateOrder",
                    2000,5000);
            if(rs!=null){
                System.out.println(Thread.currentThread().getName()+"-> 成功获得锁:"+rs);
                try {
                    Thread.sleep(1000);
                    distributedLock.releaseLockWithLua("updateOrder",rs);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                break;
            }
        }
    }

    public static void main(String[] args) {
        UnitTest unitTest=new UnitTest();
        for(int i=0;i<10;i++){
            new Thread(unitTest,"tName:"+i).start();
        }
    }
}

然后就可以执行lua脚本了。

上一篇 下一篇

猜你喜欢

热点阅读