文章目录

  • CAS
    • multi
    • watch
  • Jedis实现
  • 备选方案

CAS

  • mysql的UPDATE,hbase的checkAndPut提供CAS操作。
  • redis基于watch和multi也可以实现CAS乐观锁。

multi

  • multi:multi开启事务,包含多个命令。

    • 保证一致性、隔离性
    • 命令全部成功时保证原子性,有失败则无法保证
    • 无法保证持久性
  • exec触发。
  • 可以理解为打包的批量执行脚本。某条命令执行失败不会导致之前的命令回滚,后续命令也会继续执行。
  • 对比Pipeline:
    • multi使用服务端缓冲,每个命令发送一次给服务端,执行过程不会有其他命令穿插。
    • pipeline使用客户端缓冲,多个命令一次性发给服务端,执行过程可能有其他命令穿插。

watch

  • watch:监视key,如事务开始前key被改动,终止事务。
  • 原理:
    • 服务端维护key->watch这个key的client列表。
    • client1完成操作后会将watch这个key的列表中其他client状态设置为CLIENT_DIRTY_CAS,并把自己从列表中删除。
    • client2执行时状态为CLIENT_DIRTY_CAS直接终止事务返回失败。

Jedis实现

  • 先开watch,再开multi。
  • 根据 transaction.exec()执行结果是否都是OK,判断操作是否成功。
    • 失败则重试或者抛异常。
    • 成功则继续操作。
@Service
public class RedisCAS {@Autowiredprivate JedisPool jedisPool;private String redisKey = "cas_key";private int threadNum = 5;private ExecutorService service = Executors.newFixedThreadPool(threadNum);private CountDownLatch latch = new CountDownLatch(threadNum);private AtomicInteger successCount = new AtomicInteger(0);private AtomicInteger failCount = new AtomicInteger(0);public void execute() {//初始化keyJedis cli = jedisPool.getResource();cli.set(redisKey, String.valueOf(0));//开启5个线程for (int i = 0; i < threadNum; i++) {service.submit(new AddThread("thread-" + i));}try {latch.await();} catch (InterruptedException e) {e.printStackTrace();}System.out.println(redisKey + ": " + cli.get(redisKey));System.out.println("success: " + successCount.get() + ", fail: " + failCount.get());}public class AddThread implements Runnable {private Jedis client;private String name;public AddThread(String name) {client = jedisPool.getResource();this.name = name;}@Overridepublic void run() {try {for (int i = 0; i < 10; i++) {atomicAdd();}} catch (Exception e) {e.printStackTrace();} finally {client.close();latch.countDown();}}private void atomicAdd() {while (true) {//开启watchclient.watch(redisKey);int target = Integer.parseInt(client.get(redisKey)) + 1;//开启事务Transaction transaction = client.multi();transaction.set(redisKey, String.valueOf(target));List<Object> result = transaction.exec();//事务结果if (ok(result)) {System.out.println(this.name + " multi succussful, value = " + target);successCount.addAndGet(1);break;}System.out.println(this.name + " multi fail.");failCount.addAndGet(1);}}private boolean ok(List<Object> result) {return CollectionUtils.isNotEmpty(result) && result.stream().allMatch("OK"::equals);}}
}@Configuration
public class RedisConfig {@Beanpublic JedisPool jedisPool() {JedisPoolConfig config = new JedisPoolConfig();config.setMaxIdle(10);config.setMaxWaitMillis(1000);config.setMaxTotal(30);JedisPool jedisPool = new JedisPool(config, "127.0.0.1", 6379);return jedisPool;}
}

备选方案

  • redis悲观锁:setnx
  • 原因:
    • 由于watch需要维护key的客户端观察者列表,key修改之后修改客户端状态会有一定的开销,不适合高并发场景。
    • 某些中间件不支持watch+multi

redis实现CAS相关推荐

  1. 基于 Redis 实现 CAS 操作

    基于 Redis 实现 CAS 操作 Intro 在 .NET 里并发情况下我们可以使用 Interlocked.CompareExchange 来实现 CAS (Compare And Swap) ...

  2. 基于redis的cas集群配置(转)

    1.cas ticket统一存储 做cas集群首先需要将ticket拿出来,做统一存储,以便每个节点访问到的数据一致.官方提供基于memcached的方案,由于项目需要,需要做计入redis,根据官方 ...

  3. 使用Redis实现CAS单点登录技术方案

    什么是单点登录 单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一.SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统 ...

  4. python实现redis三种cas事务操作

    cas全称是compare and set,是一种典型的事务操作. 简单的说,事务就是为了存取数据库中同一数据时不破坏操作的隔离性和原子性,从而保证数据的一致性. 一般数据库,比如MySql是如何保证 ...

  5. python redis事务_python实现redis三种cas事务操作

    cas全称是compare and set,是一种典型的事务操作. 简单的说,事务就是为了存取数据库中同一数据时不破坏操作的隔离性和原子性,从而保证数据的一致性. 一般数据库,比如MySql是如何保证 ...

  6. Redis 使用 Lua 脚本进行原子操作

    Redis 使用 Lua 脚本进行原子操作 Intro 之前写过一篇文章也是 Redis 使用 LUA 脚本实现分布式的 CAS 操作,可以参考:基于 Redis 实现 CAS 操作 最近使用 Red ...

  7. Linux 搭建NodeBB社区,搭建CAS登录认证平台,实现Nodebb接入企业CAS认证(一)

    一,搭建Nodebb社区 1,安装编译环境nodejs,npm安装后版本号如下(同时得安装redis, git常用开发软件): 2,下载nodebb代码 git clone git://github. ...

  8. CAS单点登录(五)——Service配置及管理

    在上一节我们讲述了CAS中关于自定义认证登录策略,对CAS中关于自定义登录配置的方案,校验策略有了一定的了解,如果忘记了可以去复习一下------CAS单点登录(四)--自定义认证登录策略.这节本来该 ...

  9. java传统的项目有哪些内容_请问java全套内容都有什么呢?

    我整理的Java全套内容学习路线,分为6个阶段(大阶段)第一阶段:java内功心法篇 第二阶段:Java武功秘籍(经典框架) 第三阶段:Java高级功法(主流框架) 第四阶段:Java成神之路 第五阶 ...

  10. SpringBoot开源项目(企业信息化基础平台)

    JEEPlatform 一款企业信息化开发基础平台,可以用于快速构建企业后台管理系统,集成了OA(办公自动化).SCM(供应链系统).ERP(企业资源管理系统).CMS(内容管理系统).CRM(客户关 ...

最新文章

  1. 牛逼了!这个私藏的前端 IDE 插件,撸码 6 的飞起,编程效率提高 30 倍!
  2. 进程同步与互斥的区别
  3. 微软2016 9月笔试
  4. SpringBoot的MyBatis generator 注解方式和xml方式 (四)
  5. 解析身份证_你需要知道的与身份证相关的7个函数,让你的工作效率快速提升!...
  6. python中函数包括_python中函数都有哪些简单点的例子零基础
  7. 路由器用到坏才换?路由器你在乎哪些功能?
  8. Spring→面向切面编程AOP、相关概念、通知Advice类型、配置切面切入点通知、AOP相关API、AOP代理类ProxyFactoryBean、AOP注解@AspectJ
  9. 为eclipse3.6安装subversive插件
  10. MATLAB 格拉布斯准则代码
  11. ios刺客信条一直显示连接服务器,刺客信条本色iOS进不去怎么办
  12. excel教程自学网_超实用!良心推荐15个神级自学网站,内容全面质量又高
  13. Linux系统下QT九宫格拼图小游戏
  14. bc547可以用8050代换吗_三极管8050可用什么代替
  15. 金彩教育:详情页产品描述怎么写
  16. 逃跑吧少年维护服务器,逃跑吧少年11月19日PC端更新公告
  17. Python 编程从入门到实践 11-3
  18. 使用PyG (PyTorch Geometric) 实现同质图transductive链路预测任务
  19. 四川大学计算机学院赵怡,【喜讯】我校计算机学院学子在蓝桥杯大赛全国总决赛中再获佳绩...
  20. IBM WebSphere MQ 常见报错码及解决方案

热门文章

  1. 什么是数据抽取 --全量抽取、增量抽取
  2. 035 浅谈WebGame
  3. html5 右侧客服代码,简洁右侧栏客服代码
  4. 对接湖南CA使用U_KEY登录
  5. 挥泪告别鼠标,我终究还是学会了Windows快捷键
  6. Hybird App开发,懂得小程序+kbone+finclip就够了!
  7. 雨林木风YN9.9三分极速速终结版 http://www.51ylmf.cn
  8. html右下角图片广告,HTML580用纯JS实现右下角广告代码
  9. 计算机cpu近几年价格,2014年6月15日电脑CPU最新报价(表格)
  10. 易语言调用大漠插件判断游戏是否在线