RedisTemplate 分布式锁之使用守护线程为key续命

1、熟悉守护线程,原则:创建线程生,守护线程生;守护随创建线程,生死相随;测试代码如下

public static void main(String[] args) {
        //demo 线程测试
        Integer count = 3;
        while (count-- > 0) {
            if (count == 2) {
                Thread testThread = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Thread thread = Thread.currentThread();
                        Thread demoThread = new Thread(new Runnable() {
                            @Override
                            public void run() {
                                int countOfDemo = 0;
                                while (true) {
                                    System.out.println("守护线程活着,检测次数 " + (++countOfDemo));
                                    try {
                                        Thread.sleep(1000);
                                    } catch (InterruptedException e) {
                                        e.printStackTrace();
                                    }
                                }
                            }
                        }, "守护线程");
                        demoThread.setDaemon(true);
                        demoThread.start();
                        int counts = 10;
                        while (counts-- >=0){
                            System.out.println(Thread.currentThread().getName()+ " is alive");
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                },count.toString());
                testThread.start();
            } else {
                Thread testThread = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println("测试线程执行, " + Thread.currentThread().getName());
                        int counts = 5;
                        while (counts-- >=0){
                            System.out.println(Thread.currentThread().getName()+ " is alive");
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                },count.toString());
                testThread.start();
            }
        }
    }

测试结果如下


测试线程执行, 1
守护线程活着,检测次数 1
1 is alive
测试线程执行, 0
0 is alive
2 is alive
守护线程活着,检测次数 2
0 is alive
1 is alive
2 is alive
守护线程活着,检测次数 3
0 is alive
1 is alive
2 is alive
守护线程活着,检测次数 4
1 is alive
0 is alive
2 is alive
守护线程活着,检测次数 5
0 is alive
1 is alive
守护线程活着,检测次数 6
2 is alive
1 is alive
0 is alive
2 is alive
守护线程活着,检测次数 7
2 is alive
守护线程活着,检测次数 8
2 is alive
守护线程活着,检测次数 9
2 is alive
守护线程活着,检测次数 10
2 is alive
守护线程活着,检测次数 11
守护线程活着,检测次数 12

Process finished with exit code 0

2、redis 续命操作,直接上代码,使用RedisCluster和Jedis包实现方式类似,就不冗余写了。(可能有不完善的地方,请指正)

public Boolean tryLock(String key, String value, long expireTime) {
        try {
            //自旋上限
            int waitCount = timeout;
            while (waitCount > 0) {
                //SET命令返回OK ,则证明获取锁成功
                Boolean setIfAbsent = redisTemplate.opsForValue().setIfAbsent(key, value, expireTime, TimeUnit.SECONDS);
                if (setIfAbsent) {
                    //续命
                    Thread demo = new Thread(new Runnable() {
                        @Override
                        public void run() {
                            while (true) {
                                Boolean expire = redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
//有可能已经主动删除key,不需要在续命
                                if(!expire){
                                    return;
                                }
                                try {
                                    Thread.sleep(1000);
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    });
                    demo.setDaemon(true);
                    demo.start();
                    return true;
                }
                //否则循环等待,在timeout时间内仍未获取到锁,则获取失败
                Thread.sleep(3000);
                waitCount--;
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {

        }
        //没设置到锁,即表示超时了
        return false;
    }

unlock

    private static final String UNLOCK_SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";   
 public synchronized Boolean unlock(String key, String value) {
        logger.info("release object " + Thread.currentThread().getName());
        if (value != null) {
            // 禁止唯一value转成对象。禁止序列化 以免读取值的时候,报JSon转换错误
            value = "\"" + value + "\"";
        }
        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(UNLOCK_SCRIPT, Long.class);
        Object result = redisTemplate.execute(redisScript, Collections.singletonList(key), value);
        return Objects.equals(result, SUCCESS);
    }

 

本文地址:https://blog.csdn.net/fuwei52406/article/details/112217744

(0)
上一篇 2022年3月21日
下一篇 2022年3月21日

相关推荐