美文网首页一些收藏
分布式锁实现方案-Redis

分布式锁实现方案-Redis

作者: 洛神灬殇 | 来源:发表于2022-04-09 21:23 被阅读0次

    一.Redis分布式锁实现分析

    存在的问题:

    如果某个线程执行的太慢,导致在有效期内还没有执行完,那么因为设置了锁超时自动释放机制,此时锁被自动释放,另一个线程进来拿到锁开始执行代码,就会出现同一时间有两个线程在执行互斥资源代码,可能出现数据不一致。
    如何解决:

    设置合理的超时时间 + 监控代码执行情况
    
    自动续期,起一个定时任务,周期性扫描超距离时时间还剩多少时仍没有执行完的线程,自动延长时间。注定只能使用其他机制解决的难题
    

    二.分布式锁实现方案

    Redis锁开源实现:

    三.自己实现一个基于Redis的分布式锁

    package com.hong.redis;

    import org.springframework.beans.factory.annotation.Autowired;

    import org.springframework.dao.DataAccessException;

    import org.springframework.data.redis.connection.RedisConnection;

    import org.springframework.data.redis.connection.RedisStringCommands;

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

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

    import org.springframework.data.redis.core.types.Expiration;

    import java.util.concurrent.CountDownLatch;

    import java.util.concurrent.TimeUnit;

    import java.util.concurrent.locks.Condition;

    import java.util.concurrent.locks.Lock;

    import java.util.concurrent.locks.ReentrantLock;

    /**

    • @author wanghong

    **/

    public class RedisLockImpl implements Lock {

    @Autowired
    
    private StringRedisTemplate stringRedisTemplate;
    
    /**
    
    * 你要锁的资源
    
    */
    
    private String resourceName;
    
    int timeout;
    
    public RedisLockImpl(StringRedisTemplate stringRedisTemplate, String   
    
    resourceName, int timeout) {
    
        this.stringRedisTemplate = stringRedisTemplate;
    
        this.resourceName = "lock_" + resourceName;
    
        this.timeout = timeout;
    
    }
    
    private Lock lock = new ReentrantLock();
    
    /**
    
    * 一直要等到抢到锁为止
    
    */
    
    @Override
    
    public void lock() {
    
        // 限制同一个JVM进程内的资源竞争,分布式锁(JVM之间的竞争) + JVM锁
    
        lock.lock();
    
        try {
    
            while (!tryLock()) {
    
                // 订阅指定的Redis主题,接收释放锁的信号
    
                stringRedisTemplate.execute(new RedisCallback<Long>() {
    
                    @Override
    
                    public Long doInRedis(RedisConnection redisConnection) throws 
    
                    DataAccessException {
    
                        try {
    
                            CountDownLatch latch = new CountDownLatch(1);
    
                            // subscribe立马返回,是否订阅完毕,异步触发
    
                            redisConnection.subscribe((message, pattern) -> {
    
                                // 收到消息,不管结果,立刻再次抢锁
    
                                latch.countDown();
    
                              }, ("release_lock_" + resourceName).getBytes());
    
                            //等待有通知,才继续循环
    
                            latch.await(timeout, TimeUnit.SECONDS);
    
                        } catch (InterruptedException e) {
    
                            e.printStackTrace();
    
                        }
    
                        return 0L;
    
                    }
    
                });
    
            }
    
        } finally {
    
            lock.unlock();
    
        }
    
    }
    @Override
    
    public void lockInterruptibly() throws InterruptedException { }
    
    @Override
    
    public boolean tryLock() {
    
        // set命令,往redis存放锁的标记
    
        Boolean lockResult = stringRedisTemplate.execute(new RedisCallback<Boolean>() {
    
            @Override
    
            public Boolean doInRedis(RedisConnection redisConnection) throws DataAccessException {
    
                String value = "";
    
                Boolean result = redisConnection.set(resourceName.getBytes(),
    
                        value.getBytes(),
    
                        Expiration.seconds(timeout),
    
                        RedisStringCommands.SetOption.SET_IF_ABSENT
    
                );
    
                return result;
    
            }
    
        });
    
        return lockResult;
    
    }
    
    @Override
    
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
    
        return false;
    
    }
    
    @Override
    
    public void unlock() {
    
        stringRedisTemplate.delete(resourceName);
    
        //通过Redis发布订阅机制,发送一个通知给其他等待的请求
    
        stringRedisTemplate.execute(new RedisCallback<Long>() {
    
            @Override
    
            public Long doInRedis(RedisConnection redisConnection) throws DataAccessException {
    
                return redisConnection.publish(("release_lock_" + resourceName).getBytes(), resourceName.getBytes());
    
            }
    
        });
    
    }
    
    @Override
    
    public Condition newCondition() {
    
        return null;
    
    }
    

    }

    相关文章

      网友评论

        本文标题:分布式锁实现方案-Redis

        本文链接:https://www.haomeiwen.com/subject/iqhmsrtx.html