利用Redis实现分布式锁

实现 Redis 完成分布式锁 所用到的指令 :

  • setnx     : 如果key值不存在进行设置并返回 1,如果 key值存在不进行任何操作并返回 0
  • expire   :  给key 值设置过期时间
  • del  :  删除所对应的 key

思路:

1 . 在执行具体的买票业务之前先通过  setnx 的指令去获取其返回值,如果设置成功(返回值为1) 说明获取到了锁,没有设置成功(返回值为0),则说明没有获取到锁,继续循环执行

2. 抢到锁的线程先给key 设置过期时间,这一步主要是为了避免死锁问题(在获取锁之后释放锁之前,如果程序出现异常,则不会释放锁,就会出现死锁问题)

3. 执行具体的业务逻辑代码

4. 释放锁(删除 key )

 

具体代码的实现:

package com.tk;

import redis.clients.jedis.Jedis;

/**
 * #Description :   // 使用Redis 实现分布式锁
 * #Date: 2021/1/20 19:19
 * @author : tiankun
 */

public class RedisDistributedLock {

    public static void main(String[] args) {
        // 模拟三个黄牛买票
        new Thread(new People(),"黄牛1").start();
        new Thread(new People(),"黄牛2").start();
        new Thread(new People(),"黄牛3").start();
    }
}

/**
 * 模仿人买票
 */
class People  implements Runnable{


    private static int ticketCount = 10; // 总票数

    @Override
    public void run() {
        Jedis jedis = new Jedis("192.168.112.134", 6379);
        // 1. 获取锁
        Long lock = 0L;
        while (ticketCount > 0){
            while (true){
                // 模拟买票的间隔时间
                // 注意:这个模拟买票的间隔时间必需写在逻辑代码前面,这样才能保证每个黄牛都会具有相同的间隔时间,如果放在最后,抢到锁的线程就不会sleep,会出现总是一个人抢到锁的情况
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                // 当没有票的时候让其他黄牛退出死循环
                if(ticketCount < 1){
                    System.out.println("没有票了");
                    break;
                }
                // 如果获取到锁继续执行业务逻辑(购买票)
                lock = jedis.setnx("ticket","true");
                System.out.println(Thread.currentThread().getName()+" ==> "+lock);

                if(lock == 1){
                    // 2. 给锁设置过期时间避免发生死锁问题
                    jedis.expire("ticket",2);
                    break;
                }
            }

            // 防止最后一张票被重复购买的问题
            if(ticketCount < 1){
                System.out.println("没有票了");
                break;
            }

            // 3.执行购买票业务逻辑
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            buyTicket();
            // 4. 释放锁
            jedis.del("ticket");
        }
    }

    /**
     * 购买票
     */
    private void buyTicket(){
        try {
            // 模拟网络延迟
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"购买了票,剩余的票数为"+(--ticketCount));
    }
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值