使用redis实现分布式锁

前言;

 

 

redis实现分布式锁常见问题

1、不是原子操作

2、没有设置失效时间导致服务异常停止的情况下redis设置的锁(key)一直存在

3、业务未执行完成就释放了锁,(锁设置时间比业务执行时间短导致,解决方式之一是定时检查锁是否存在如果存在则重写设置生效时长)

4、释放了别人的锁(在多线程并发下没有判断释放的锁是自己的直接释放可能导致释放别人的锁、导致锁失效)

一、使用StringRedisTemplate实现分布式锁

解决了:3、4

package com.example.baidu.redis;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

@RestController
public class RedisController {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @GetMapping("/redis")
    public void sendMessage(@RequestParam String message) {
        String clientId = UUID.randomUUID().toString();
        Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(message, clientId, 10, TimeUnit.SECONDS);
        if (!result) {
            System.out.println("获取锁失败!");
        } else {
            try {
                Thread.sleep(100000);
            } catch (InterruptedException e) {
                ;
                e.printStackTrace();
            } finally {
                if (clientId.equals(stringRedisTemplate.opsForValue().get(message))) {
                    stringRedisTemplate.delete(message);
                }
            }
        }


    }

}

 

二、使用Redisson实现分布式锁

解决了:1、2、3、4

package com.example.baidu.redis;

import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.concurrent.TimeUnit;


@Controller
public class RedissonController {


    @GetMapping("/redisson")
    @ResponseBody
    public int redisson() {
        testThreadLock();
        return 0;
    }


    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private Redisson redisson;


    public void lock(String key, String num) {

        //获取锁
        RLock lock = redisson.getLock(key);
        boolean locked = false;
        try {
            //设置锁
            locked = lock.tryLock(10, TimeUnit.SECONDS);
            //locked = lock.lock();
            if (locked) {
                //开始写业务
                System.out.println(num + "锁住了。。。");
                System.out.println(num + "模拟业务耗时开始。。");
                Thread.sleep(10);
                System.out.println(num + "模拟业务耗时结束。。。");
            } else {
                System.out.println(num + "没锁住。。。");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (locked) {
                System.out.println(num + "释放锁");
                System.out.println();
                lock.unlock();
            }
        }
    }


    public void testThreadLock() {
        String key = "threadLock";
        for (int i = 1; i < 100; i++) {
            new Thread() {
                @Override
                public void run() {
                    lock("test", this.getName());
                }
            }.start();
        }
    }
}

 

posted @ 2022-07-03 16:53  银河系的极光  阅读(182)  评论(0)    收藏  举报