美文网首页
《redis in action》——锁

《redis in action》——锁

作者: 墨荒 | 来源:发表于2018-06-07 18:54 被阅读0次

redis测试项目搭建

新建项目

http://start.spring.io/填写项目标识、添加redis依赖,下载项目用idea打开

配置redis

  • 启动本地redis服务器
  • 在application.properties文件添加配置
spring.redis.host=127.0.0.1
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接超时时间(毫秒)
spring.redis.timeout=30000
  • 测试redis是否可用
public class RedisConnectTest extends RedisApplicationTests{
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Test
    public void testRedis() throws Exception {
        stringRedisTemplate.opsForValue().set("a", String.valueOf(1));
        System.out.println(stringRedisTemplate.opsForValue().get("a"));
    }
}

场景

定义锁的工具类接口

public interface LockHelper {
    void lock(String key);
    void unLock(String key);
}

调用的时候注意在finally的时候释放锁,避免业务执行失败时没释放所导致死锁

            try {
                lockHelper.lock(account.id);
                super.run();
            }finally {
                lockHelper.unLock(account.id);
            }

本地锁

ConcurrentHashMap+ReentrantLock:

@Component("LocalLockHelper")
public class LocalLockHelper implements LockHelper {
    private ConcurrentHashMap<String,Lock> lockMap = new ConcurrentHashMap<>();
    @Override
    public void lock(String key) {
        Lock lock = lockMap.get(key);
        if(lock == null){
            Lock newLock = new ReentrantLock();
            Lock existLock = lockMap.putIfAbsent(key,newLock);
            //锁不存在的话就用新锁,存在的话用旧锁
            lock = existLock == null?newLock:existLock;
        }
        lock.lock();
    }
    @Override
    public void unLock(String key) {
        Lock lock = lockMap.get(key);
        if(lock != null){
            lock.unlock();
        }
    }
}

redis锁

加锁多了个支持锁过期的方法,防止分布式情况下一些客户端没有(成功)释放锁,甚至在第一次申请锁的时候对应的key已经存在。

@Component("RedisLockHelper")
public class RedisLockHelper implements LockHelper,ExpireLock{
    @Autowired
    private StringRedisTemplate redisTemplate;
    private Map<String, String> keyMap = new HashMap<>();

    @Override
    public void lock(String key) {
        BoundValueOperations<String,String> boundValueOperations =
                this.redisTemplate.boundValueOps(getLockKey(key));
        while (true) {
            if (boundValueOperations.setIfAbsent(this.getRequestId())) {
                break;
            }else {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     *设置持有锁的超时时间,防止某些客户端未释放锁
     */
    @Override
    public void lock(String key, long expireTimeMills) {
        BoundValueOperations<String,String> boundValueOperations =
                this.redisTemplate.boundValueOps(getLockKey(key));
        while (true) {
            if (boundValueOperations.setIfAbsent(this.getRequestId())) {
                boundValueOperations.expire(expireTimeMills, TimeUnit.MILLISECONDS);
                break;
            }else {
                long wait;
                if (boundValueOperations.getExpire() == -1) {
                    System.out.println(key+"|"+Thread.currentThread().getName()+"设置锁超时时长");
                    //防止未释放锁
                    wait = expireTimeMills;
                    boundValueOperations.expire(expireTimeMills, TimeUnit.MILLISECONDS);
                }else{
                    wait = 100;
                }
                try {
                    Thread.sleep(wait);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    public void unLock(String key) {
        String lk = getLockKey(key);
        BoundValueOperations<String,String> boundValueOperations =
                this.redisTemplate.boundValueOps(lk);
        if(this.getRequestId().equals(boundValueOperations.get())) {
//            释放锁的时候检测当前值是否为请求id,防止被其他请求释放,这个地方应该用lua脚本 把检查和删除 做成一个有原子性的方法或者命令
            redisTemplate.delete(lk);
        }
    }

    private String getRequestId() {
        //多实例情况下需要设置为http requestId之类的
        return String.valueOf(Thread.currentThread().getId());
    }

    private String getLockKey(String key) {
        String t = keyMap.get(key);
        if(t == null){
            t = "lock:"+key;
            keyMap.put(key,t);
        }
        return t;
    }
}

相关文章

  • 《redis in action》——锁

    redis测试项目搭建 新建项目 http://start.spring.io/填写项目标识、添加redis依赖,...

  • 如何在springcloud分布式系统中实现分布式锁?

    最近在看分布式锁的资料,看了 Josial L的《Redis in Action》的分布式锁的章节。实现思路是利用...

  • redis 相关

    推荐图书Redis in Action An introduction to Redis data types a...

  • Redis in Action

    Ref: Redis in Action Redis是我在大约3年前为了解决一个实际问题而创造出来的:简单来说,当...

  • 秒杀随笔

    方法: mysql悲观锁 mysql乐观锁 PHP+redis分布式锁 PHP+redis乐观锁(redis wa...

  • 大佬浅谈分布式锁

    redis 实现 redis 分布锁一、redis 实现分布式锁(可重入锁)redission 实现分布式锁1、对...

  • Redis实现分布式锁

    Redis实现分布式锁 一、Redis单节点实现 (一) 获取锁 使用 Redis 客户端获取锁,向Redis发出...

  • Redis入门

    内容来自Redis实战(Redis in Action)。 一、介绍 Redis 是一个开源的使用 ANSI C ...

  • 分布式锁之redis-lua脚本

    目录 redis分布式锁,Lua,Lua脚本,lua redis,redis lua 分布式锁,redis set...

  • redis锁

    1、单节点的redis锁优点:快缺点:不安全(redis节点断电,网络不通,锁过期等等) 2、多节点redis锁,...

网友评论

      本文标题:《redis in action》——锁

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