分布式锁

  为什么需要有分布式锁呢,在单点的时候synchronized 就能解决,但是服务拆分之后,每个服务都是单独的机器,无法解决,所以出现了分布式锁,其实也就是用各种手段,实现获取唯一锁,别人无法得到。

  其实在做分布式锁的前提,需要先明白,synchronized  为啥不能使用了,啥原理让他在一个机器上可以使用。

  


synchronized 的原理   

众所周知 Synchronize 关键字是解决并发问题常用解决方案,有以下三种使用方式:

  • 同步静态方法,锁的是当前 Class 对象。
  • 同步块,锁的是 {} 中的对象。
  • 同步普通方法,锁的是当前对象。

  实现原理:
  JVM 是通过进入、退出对象监视器( Monitor )来实现对方法、同步块的同步的。

  具体实现是在编译之后在同步方法调用前加入一个 monitor.enter 指令,在退出方法和异常处插入 monitor.exit 的指令。

  其本质就是对一个对象监视器( Monitor )进行获取,而这个获取过程具有排他性从而达到了同一时刻只能一个线程访问的目的。

  而对于没有获取到锁的线程将会阻塞到方法入口处,直到获取锁的线程 monitor.exit 之后才能尝试继续获取锁。

可以通过使用 javap -c Synchronize 可以查看编译之后的具体信息 ,这里我就不再粘贴了。

所以可以知道,单独的Java虚拟机是可实现锁的,但是多台手就伸不到了,只能在依赖外部的形式去产生一个唯一锁。

以上是参考别人的博客拿到的信息,亲自试用得到,准确   :链接:https://www.jianshu.com/p/2ba154f275ea


  Redis实现的分布式锁

  主要是利用了redis的set NX的原理,以及对redis的script脚本原子性利用。(个人看法,其实后面一步就看各自的程序逻辑如何去判定到底要不要这一步了)

  简单的说一下主要流程:

  1. 首先设置一个全局唯一的key和一个唯一性的value(value是一个解锁的保障,删除之前判断一下值是否一致)
  2. 使用Redis的set 方法 以多参数形式配置key,value,nx,px,过期时间 (参数 NX:只有键不存在时,才能对其进行设置操作)
  3. 利用Redis的script脚本来对key的删除操作,只能自己删除自己的value(删除之前先判断一下value是否是我之前的value,是否被改过,没有就删了)

   这是脚本的主要 内容 if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1]) else  return 0 end

   对其解释: 根据 get 获取到 key 的值 ,判断key的值是否跟你传的值相等,相等则 执行del  key 否则返回0 结束
   对此推荐去看一下redis的Lua脚本,给个简单的:http://redisdoc.com/script/eval.html
  
  在实际场景中可以利用AOP的切点切面形式,实现具体是什么地方需要分布式锁,搭配分布式锁,再搭配注解方式,来实现想要的自定义设置那里需要就点哪里
  AOP的主要实现是
  1. @pointcut 切注解类
  2. 在使用@around环绕对前后做处理
  3. 前面加锁
  4. 后面解锁del  使用script脚本
  

  代码主要实现

  注解类 DistributedLock

  

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface DistributedLock { /**
* 自定义形式添加你对分布式锁的对外配置属性
* 例如:key的规则,锁的超时时间,获取锁的等待时间,等一系列的属性配置
*
*/ }
  切面类 DistributedLockAspect
@Aspect
@Component
public class DistributedLockAspect { /**
* 层切点
*/
@Pointcut("@annotation(com.creditease.hardess.common.annotation.DistributedLock)")
public void distributedLockAspect() {} /**
* @param joinPoint 切点
* @return Object 添加分布式锁后,实际调用业务逻辑部分代码的返回值
* @throws Throwable 产生的所有异常,为了避免对异常处理流程产生干扰,所有异常都应该继续抛出
*/
@Around("distributedLockAspect()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
/**
*主要写一些锁的获取,和业务逻辑执行,锁的删除等
*
*/
return returnObject;
} /**
* 获取 DistributedLock 注解
*
* @param joinPoint
* @return 代码中定义的注解
* @throws NoSuchMethodException
*/
private static DistributedLock getDistributedLock(ProceedingJoinPoint joinPoint)
throws NoSuchMethodException {
String methodName = joinPoint.getSignature().getName(); Class<?> classTarget = joinPoint.getTarget().getClass();
Class<?>[] par = ((MethodSignature) joinPoint.getSignature()).getParameterTypes();
Method objMethod = classTarget.getMethod(methodName, par); return objMethod.getAnnotation(DistributedLock.class);
} } }

分布式锁----Redis实现的更多相关文章

  1. 分布式锁--Redis小试牛刀

    参考文章: Redis分布式锁的正确实现方式 分布式锁看这篇就够了 在这两篇文章的指引下亲测 Redis分布式锁 引言 分布式系统一定会存在CAP权衡问题,所以才会出现分布式锁 什么是CAP理论? 为 ...

  2. Redis除了做缓存--Redis做消息队列/Redis做分布式锁/Redis做接口限流

    1.用Redis实现消息队列 用命令lpush入队,rpop出队 Long size = jedis.lpush("QueueName", message);//返回存放的数据条数 ...

  3. java-spring基于redis单机版(redisTemplate)实现的分布式锁+redis消息队列,可用于秒杀,定时器,高并发,抢购

    此教程不涉及整合spring整合redis,可另行查阅资料教程. 代码: RedisLock package com.cashloan.analytics.utils; import org.slf4 ...

  4. 分布式锁redis

    1. 首先看这篇文章中  https://mp.weixin.qq.com/s/s-ozSjM5WmSUopxttSWYeQ 为什么redis能实现锁功能呢,看下图,redis命令窗口中,setnx  ...

  5. 分布式锁-Redis方案

    #!/usr/bin/env python # coding=utf-8 import time import redis class RedisLock(object): def __init__( ...

  6. Lua脚本在redis分布式锁场景的运用

    目录 锁和分布式锁 锁是什么? 为什么需要锁? Java中的锁 分布式锁 redis 如何实现加锁 锁超时 retry redis 如何释放锁 不该释放的锁 通过Lua脚本实现锁释放 用redis做分 ...

  7. Redis 分布式锁的实现

    0X00 测试环境 CentOS 6.6 + Redis 3.2.10 + PHP 7.0.7(+ phpredis 4.1.0) [root@localhost ~]# cat /etc/issue ...

  8. 分布式交易系统的并发处理, 以及用Redis和Zookeeper实现分布式锁

    交易系统 交易系统的数据结构 支付系统API通常需要一个“订单号”作为入参, 而实际调用API接口时使用到的往往不是真正意义的业务订单号, 而是交易订单号.  支付系统的API会使用“商户号+订单号” ...

  9. 基于zookeeper或redis实现分布式锁

    前言 在分布式系统中,分布式锁是为了解决多实例之间的同步问题.例如master选举,能够获取分布式锁的就是master,获取失败的就是slave.又或者能够获取锁的实例能够完成特定的操作. 目前比较常 ...

随机推荐

  1. 自己动手写jQuery插件---Tip(提示框)

    对jQuery相信很多同学和我一样平时都是拿来主义,没办法,要怪只能怪jQuery太火了,各种插件基本能满足平时的要求.但是这毕竟不是长久之道,古人云:“授之以鱼,不如授之以渔”. 为了方便之前没有接 ...

  2. Java基础(四) StringBuffer、StringBuilder原理浅析

    StringBuilder与StringBuffer作用就是用来处理字符串,但String类本身也具备很多方法可以用来处理字符串,那么为什么还要引入这两个类呢? 关于String的讲解请看Java基础 ...

  3. hive数据倾斜的解决办法

    数据倾斜是进行大数据计算时常见的问题.主要分为map端倾斜和reduce端倾斜,map端倾斜主要是因为输入文件大小不均匀导致,reduce端主要是partition不均匀导致. 在hive中遇到数据倾 ...

  4. 07 jQuery的位置信息

    一.宽度和高度 获取宽度 .width() 描述:为匹配的元素集合中获取第一个元素的当前计算宽度值.这个方法不接受任何参数..css(width) 和 .width()之间的区别是后者返回一个没有单位 ...

  5. 09 audio和vedio标签

    <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8& ...

  6. Metasploit渗透测试

    原创博客,转载请注出处! 学习笔记 参考书籍<Metasploit渗透测试指南(修订版)> 经过多日学习,初步掌握metasploit基本参数和使用方法,现进行渗透测试实践 靶机IP:16 ...

  7. Docker入门简介(一)

    Docker 介绍 Docker是Docker.lnc公司开源的一个基于LXC技术智商构建的Container容器引擎,源代码托管在GitHub上,基于Go语言并遵从Apache2.0协议开源. Do ...

  8. 为什么Java只有值传递?

    形参和实参 形式参数,是在方法定义阶段,是定义某个函数时使用的参数,用于接收实参传入.例f(x,y)中x和y是形参. 实际参数,是在方法调用阶段,是主调函数调用有参函数时,实际传递的内容.例f(3,7 ...

  9. Java web导出word,文件名为中文,%E6%9D%90%E8%B4%A8%E5%8D%95乱码

    因为文件名为中文,导出时会有乱码问题 原代码: String fileName = "文件名.doc"; response.setHeader("Content-Disp ...

  10. 剑指offer第二版-9.用两个栈实现队列

    描述:使用两个栈实现一个队列.队列中实现尾部插入和头部删除函数. 思路:stack1负责插入,stack2负责弹出,如果stack2为空了,将stack1的元素依次弹出并存放到stack2中,之后对s ...