java redis知识-redis乐观锁

锁机制

乐观锁:1)通过版本号来实现,先查询获取版本号,在更新的时候校验版本号并修改。

悲观锁:同步关键字就是悲观锁,也称为排它锁。

乐观锁还让用户查询当前版本号,悲观锁如果不释放,查都不让查询。

乐观锁存在多种实现方式:mysql数据库版本号,redis实现,CAS实现等。

在并发情况下,使用锁机制,防止争抢资源。

悲观锁是对数据的修改持悲观态度(认为数据在被修改的时候一定会存在并发问题),因此在整个数据处理过程中将数据锁定。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在应用层中实现了加锁机制,也无法保证外部系统不会修改数据)

在限量秒杀抢购的场景,一定会遇到抢购成功数超过限量的问题和高并发的情况影响系统性能

1、虽然能用数据库的锁避免,超过限量的问题。但是在大并发的情况下,大大影响数据库性能
2、为了避免并发操作数据库,我们可以使用队列来限制,但是并发量会让队列内存瞬间升高
3、我们又可以用悲观锁来实现,但是这样会造成用户等待,响应慢体验不好

因此我们可以利用redis来实现乐观锁

代码实现

案例一

这里我用java实现,我开20个线程模拟10000个人并发来抢购,其它语言也是一样的实现原理。

public static void main(String[] arg){
    String redisKey = "redisTest";
    ExecutorService executorService = Executors.newFixedThreadPool(20);
    try {
        Jedis jedis = new Jedis("47.107.221.219",6379);
        jedis.set(redisKey,"0");
        jedis.close();
    }catch (Exception e){
        e.printStackTrace();
    }

    for (int i=0;i<10000;i++){
        executorService.execute(()->{
            Jedis jedis1 = new Jedis("47.107.221.219",6379);
            try {
                jedis1.watch(redisKey);
                String redisValue = jedis1.get(redisKey);
                int valInteger = Integer.valueOf(redisValue);
                String userInfo = UUID.randomUUID().toString();
                if (valInteger<20){
                    Transaction transaction = jedis1.multi();
                    transaction.incr(redisKey);
                    List list = tx.exec();
                    if (list!=null){
                        System.out.println("用户:"+userInfo+",秒杀成功!当前成功人数:"+(valInteger+1));
                    }else {
                        System.out.println("用户:"+userInfo+",秒杀失败");
                    }
                }else {
                    System.out.println("已经有20人秒杀成功,秒杀结束");
                }
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                jedis1.close();
            }
        });
    }
    executorService.shutdown();
}

案例二

public void testRedisSyn(int clientName,String clientList) {
 
        //redis中存储商品数量为(goodsNum:100)
        String key = "goodsNum";
        Jedis jedis = new Jedis("192.168.140.98", 6379);
        jedis.auth("redis密码");
 
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
 
        while (true) {
            try {
                jedis.watch(key);
                System.out.println("顾客:" + clientName + "开始抢商品");
                System.out.println("当前商品的个数:" + jedis.get(key));
                //当前商品个数
                int prdNum = Integer.parseInt(jedis.get(key));
                if (prdNum > 0) {
 
                    //开启事务,返回一个事务控制对象
                    Transaction transaction = jedis.multi();
                    //预先在事务对象中装入要执行的操作
                    transaction.set(key, String.valueOf(prdNum - 1));
                    List<Object> exec = transaction.exec();
                    if (exec == null || exec.isEmpty()) {
                        //可能是watch-key被外部修改,或者是数据操作被驳回
                        System.out.println("悲剧了,顾客:" + clientName + "没有抢到商品");
                    } else {
                        //这个命令是做啥的。//抢到商品记录一下
                        jedis.sadd(clientList, clientName+"");
                        System.out.println("好高兴,顾客:" + clientName + "抢到商品");
                        break;
                    }
                }
            } catch (NumberFormatException e) {
                e.printStackTrace();
            }finally {
                jedis.unwatch();
            }
        }
 
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
分布式锁是在分布式系统中用于解决并发访问共享资源的问题的一种机制。在Java中,可以使用Redis实现分布式锁。有几种常见的实现方式。 一种方式是使用RedisTemplate来操作Redis,通过调用opsForValue().setIfAbsent()方法来尝试获取锁。如果返回true,则表示获取锁成功,可以执行业务逻辑;如果返回false,则表示获取锁失败,需要等待一段时间后重试。在执行完业务逻辑后,需要调用redisTemplate.delete()方法来释放锁。这种方式需要注意的是,获取锁和释放锁的操作需要在同一个Redis连接中进行,以保证原子性。[1] 另一种方式是直接使用Jedis来操作Redis。通过调用setnx()方法来尝试获取锁,如果返回1,则表示获取锁成功,可以执行业务逻辑;如果返回0,则表示获取锁失败,需要等待一段时间后重试。在执行完业务逻辑后,需要调用jedis.del()方法来释放锁。这种方式也需要注意获取锁和释放锁的操作需要在同一个Redis连接中进行,以保证原子性。[2] 需要注意的是,分布式锁的实现需要考虑到并发情况下的线程安全性和可靠性。在使用分布式锁时,还需要考虑锁的超时时间和重试机制,以防止死锁和长时间等待的情况发生。 总结起来,Java通过Redis实现分布式锁的方式有多种,可以使用RedisTemplate或者直接使用Jedis来操作Redis。具体选择哪种方式取决于项目的需求和技术栈的选择。[1][2][3]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值