基于Redis的分布式锁的简单应用

基于Redis的分布式锁

  1. 支持分布式
  2. 可以细粒度话的控制
  3. 实现多台机器多个进程对一个数据进行操作的互斥(存放于Redis存储系统,多台机器的业务可以共同到Redis系统上进行基于分布式锁的业务操作)

处理并发问题

处理并发问题,主要就是不发生异常的情况下,想办法提升访问速度。

第一种,可以提前把数据库中的数据以Map的形式加载到内存,处理完之后再将处理结果统一写入数据库,提高访问数据的速度。

第二种,使用数据库,要在对应使用线程的方法上加上Synchronized,使其变为单线程,保证了数据的一致性。

如下例子表示的秒杀下单的例子,为该方法加上synchronized:

public synchronized void orderProductMockDiffUser(StringproductId)
{
   
{
    //1:查询该商品库存,0表示活动结束
    int stockNum=stock.get(productId);
    if(stockNum==0){
       
        thrownew SellException(100,"活动结束");
   
    }
   
    else{
       
        //2:下单,(不同用户的openid不同)
        orders.put(KeyUtil.genUniquekey().productId);
       
        stockNum--;
        try
        try{
            Thread.sleep(
            Thread.sleep(100);
       
        }
        
        catch(InterruptedException e){
            e.printStackTrace()
            e.printStackTrace();
       
        }
        Stock.put(productid
        Stock.put(productid,stockNum);
   
    }
}
}

上述第二种办法,是一种解决办法,但是还是有问题,这种情况只适合单点秒杀的情况。无法细粒度控制一些秒杀的情况。比如,一起秒杀的线程秒杀不同的商品,有的秒杀用户多,有的秒杀用户少,这种情况就会导致所有的秒杀一样的速度,忽略了那些用户少的情况。因此,需要根据情况个别对待,提高效率,这时就需要基于Redis的分布式锁来解决这个问题了。

Redis

百度百科这样解释Redis的:

      Redis是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。它支持多种类型的数据结构,如 字符串(strings, 散列(hashes, 列表(lists集合(sets, 有序集合(sorted sets 与范围查询, bitmaps, hyperloglogs  地理空间(geospatial 索引半径查询。 Redis 内置了 复制(replicationLUA脚本(Lua scriptingLRU驱动事件(LRU eviction事务(transactions 和不同级别的 磁盘持久化(persistence并通过 Redis哨兵(Sentinel和自动 分区(Cluster提供高可用性(high availability)。

首先要认识两个Redis的命令:

1)SETNX命令

命令形式:SETNX KEYVALUE

意思是:

                      

该例子:在redis存储系统中,将mykey设置为“Hello”,返回1表示设置成功。重新给该key设置为world,不成功,因为已经存在了键值,则什么也不做,返回了0。GET KEY查询到key的value值为“Hello”;

2)GETSET命令

命令形式:GETSET keyvalue

意思是:

                

基于Redis的加解锁

 

加锁方法lock()

参数 key:传递的是商品productId,value:当前时间+超时时间,保证在上一个线程正常解锁时间之后。

首先在redis中进行键值对的设置(SETNX命令),返回true表示加锁成功,设置时间为value。

否则,获取redis中已有key对应的value值,如果其值不为空并且小于系统当前时间,表示上一个线程的锁已经过期了,此时应该重新设置覆盖以前redis中key的value值(对应Redis中GetAndSet命令),此时当前线程可以抢占锁了。

此时如果有多个线程抢占加锁,则每个线程都需要利用getAndSet得到的旧时间值来个当前key对应的时间值比较,如果相等,表示就是自己拿到的上一个锁的解锁时间,可以抢占加锁;如果不相等,则表示被其他线程捷足先登了,此时不可加锁,需要等到起解锁。

解锁方法unlock()

参数 key:传递的是商品productId,value:当前时间+超时时间,保证在上一个线程正常解锁时间之后。

判断当前商品加锁时间是否为空,如果不为空则并且等于当前传入的value时间戳的值则表示上一个锁已经过期了,此时可以直接删除redis中上一个线程的锁,以释放给其他线程来使用。

业务加解锁

对下单的方法进行加解锁:

public synchronized void orderProductMockDiffUser(StringproductId)
{
    //加锁
    longtime =System.currentTimeMillis()+TIMEOUT;
    if(!redisLock.lock(productId.String.valueOf(time)))
    {
        Throw new SellException(101,"人太多了,换个姿势再试试")
    }


    //1:查询该商品库存,0表示活动结束
    int stockNum=stock.get(productId);
    if(stockNum==0){
        thrownew SellException(100,"活动结束");
    }
    else{
        //2:下单,(不同用户的openid不同)
        orders.put(KeyUtil.genUniquekey().productId);
        stockNum--;
        try{
            Thread.sleep(100);
        }
        catch(InterruptedException e){
            e.printStackTrace();
        }
        Stock.put(productid,stockNum);
    }

    //解锁
    redisLock.unlock(productId,String.valueOf(time));
}
 

 

 Redis数据缓存

这一部分见  高并发优化Redis缓存部分

Jpa和Mybatis怎么选?

JPA:小型项目

Mybatis:SSM架构的则继续使用

建表格使用sql,不用JPA建立,因为不够直观,所以选择Mybatis.

压测模拟并发

Apache ab模拟并发,直接在命令行输入如下命令:

ab -n 100 -c 100 url地址      表示 模拟100条请求的url有100个人同时请求

ab -t 60 -c 100 url地址         表示模拟60秒内100个人同时发送请求  

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值