本文是通过watch(监控)+mutil(事务)实现应用于在分布式高并发处理等相关场景 。下边先通过redis-cli.exe来测试多个线程修改时 , 遇到问题及解决问题 。
高并发下修改同一个key遇到的问题:
1)定义一个hash类型的key , key为:lock_test , 元素locker的值初始化为0 。
2)实现高并发下对locker元素的值递增:定义64个多线程 , 并发的对lock_test元素locker的值进行修改 。
package com.dx.es;import JAVA.util.concurrent.CountDownLatch;import redis.clients.jedis.Jedis;import redis.clients.jedis.JedisPool;public class Test_UnLock { public static void main(String[] args) { final JedisPool pool = RedisUtil.getPool(); // 获得jedis对象 Jedis jedis = pool.getResource(); jedis.hset("lock_test", "locker", "0"); String val = jedis.hget("lock_test", "locker"); System.out.println("lock_test.locker的初始值為:" + val); jedis.close(); int threahSize = 64; final CountDownLatch threadsCountDownLatch = new CountDownLatch(threahSize); Runnable handler = new Runnable() { public void run() { Jedis jedis = pool.getResource(); Integer integer = Integer.valueOf(jedis.hget("lock_test", "locker")); jedis.hset("lock_test", "locker", String.valueOf(integer + 1)); jedis.close(); threadsCountDownLatch.countDown(); } }; for (int i = 0; i < threahSize; i++) { new Thread(handler).start(); } // 等待所有并行子线程任务完成 。try { threadsCountDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("complete"); val = jedis.hget("lock_test", "locker"); System.out.println(val); }}RedisUtil.java
package com.dx.es;import redis.clients.jedis.JedisPool;import redis.clients.jedis.JedisPoolConfig;public class RedisUtil { public static JedisPool getPool() { // 简单创建 Jedis的方法: // final Jedis jedis = new Jedis("127.0.0.1",6379); // 下边使用线程池的方案:jedis对象是线程不安全的 , 因此在并发情况下要使用JedisPool,默认情况下jedisPool只支持8个连接 , 因此在声明JedisPool时要先修改JedisPool的最大连接数 JedisPoolConfig config = new JedisPoolConfig(); // 修改最大连接数 config.setMaxTotal(32);// 声明一个线程池 JedisPool pool = new JedisPool(config, "127.0.0.1", 6379); return pool; }}此时 , 会出现以下问题:
- A线程获取key的值为0 , 而B线程也获取jkey的值0 , 则A把key值递增为1 , B线程也实现把key值递增为1 。两个线程都执行了key值修改:0到1 。
- 在1)中最终key修改为了1 , 但是c线程获取key的值为0(因为c线程读取key值时 , a、b线程还未触发修改 , 因此c线程读取到的值为0) , 此时d线程读取到的值为1(因为d线程读取key值时 , a、b线程已触发修改 , 一次d线程取到的值为1) 。
- 此时假设d线程优先触发递增 , 则在c线程未触发提交之前d线程已经把值修改了2 , 但是c此时并不知道在它获取到值到修改之前这段时间发生了什么 , 直接把值修改1 。
lock_test.locker的初始值為:0complete24 #备注:也可能是其他值 , 可能是正确值64的可能性比较小 。通过watch+mutil解决并发修改的问题:
需要掌握Redis 事务命令:
文章插图
Redis 事务可以一次执行多个命令 , 并且带有以下两个重要的保证:
- 批量操作在发送 EXEC 命令前被放入队列缓存 。
- 收到 EXEC 命令后进入事务执行 , 事务中任意命令执行失败 , 其余的命令依然被执行 。
- 在事务执行过程 , 其他客户端提交的命令请求不会插入到事务执行命令序列中 。
- 开始事务 。
- 命令入队 。
- 执行事务 。
redis-cli.exe下的事务操作:
# 事务被成功执行redis 127.0.0.1:6379> MULTIOKredis 127.0.0.1:6379> INCR user_idQUEUEDredis 127.0.0.1:6379> INCR user_idQUEUEDredis 127.0.0.1:6379> INCR user_idQUEUEDredis 127.0.0.1:6379> PINGQUEUEDredis 127.0.0.1:6379> EXEC1) (integer) 12) (integer) 23) (integer) 34) PONG并发情况下使用watch+mutil操作:
事务块内所有命令的返回值 , 按命令执行的先后顺序排列 。当操作被打断时 , 返回空值 nil。
推荐阅读
- 男性生殖器上长疙瘩该怎么解决呢?
- 酵素|解决头发打结、毛燥、掉落,5个保养方法重拾光泽柔顺的发质!
- 玩LOL电脑很卡怎么办?解决方案五步走 玩英雄联盟卡怎么办
- 不花钱,这波操作帮你轻松解决 apple id密码忘了
- 淘宝直播流量突然下降怎么解决 淘宝直播间流量突然下降
- redis事务不具有回滚机制,那么它是如何进行事务控制的
- 微信 小程序 POST请求中文乱码的解决方法
- 怎么解决 无法访问 您可能没有权限使用网络资源
- 分布式 MIMO 与无蜂窝移动通信
- office2007软件打开时弹出报错SETUP ERROR的解决方法