JAVA RedisTemplate实现(加锁/解锁) 解决高并发问题
基于传统的单机模式下的并发锁,已远远不能满足当下高并发大负载的情况,当下常用的并发处理如下
1、使用synchronized关键字
2、select for update 乐观锁
3、使用redis实现同步锁
方案一 适合单机模式,
方案二 虽然满足多节点服务实例但 对变更操作的吞吐量有影响
方案三 基于redis nosql数据库 在效率与横向扩展方面都大大优于前两种方案
redis 单线程 在自身设计上一定程度可避免想成不安全 再者其效率高于关系型数据库
本次实现锁机制 基于redis 的两个指令 查询 redis.cn 网站
指令一:SETNX key value
将key
设置值为value
,如果key
不存在,这种情况下等同SET命令。 当key
存在时,什么也不做。SETNX
是”SET if Not eXists”的简写。
返回值
Integer reply, 特定值:
1
如果key被设置了0
如果key没有被设置
指令二:GETSET key value
自动将key对应到value并且返回原来key对应的value。如果key存在但是对应的value不是字符串,就返回错误。
返回值
bulk-string-reply: 返回之前的旧值,如果之前Key
不存在将返回nil
。
步骤一, pom文件
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId><version>2.6.0</version></dependency>
步骤二,RedisCacheAutoConfiguration
package com.wh.whcloud.df.config;import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wh.whcloud.core.redis.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;/*** Redis缓存配置** @author */
@Slf4j
@Configuration
@AutoConfigureAfter({RedisAutoConfiguration.class})
public class RedisCacheAutoConfiguration {/*** 重新配置一个RedisTemplate** @param factory* @return*/@Beanpublic RedisTemplate redisTemplate(RedisConnectionFactory factory) {RedisTemplate template = new StringRedisTemplate();template.setConnectionFactory(factory);Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);ObjectMapper om = new ObjectMapper();om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(om);RedisSerializer<String> stringSerializer = new StringRedisSerializer();// key采用String的序列化方式template.setKeySerializer(stringSerializer);// hash的key也采用String的序列化方式template.setHashKeySerializer(stringSerializer);// value序列化方式采用jacksontemplate.setValueSerializer(jackson2JsonRedisSerializer);// hash的value序列化方式采用jacksontemplate.setHashValueSerializer(jackson2JsonRedisSerializer);template.setDefaultSerializer(jackson2JsonRedisSerializer);log.info("RedisTemplate配置 [{}]", template);return template;}@Bean@ConditionalOnMissingBean(RedisUtil.class)@ConditionalOnBean(RedisTemplate.class)public RedisUtil redisUtils(RedisTemplate redisTemplate) {RedisUtil redisUtil = new RedisUtil(redisTemplate);log.info("RedisUtil [{}]", redisUtil);return redisUtil;}
}
步骤三, RedisLock 加解锁实现
package com.wh.whcloud.util;import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import java.util.Collections;
import java.util.concurrent.TimeUnit;public class RedisLock {private static final Long SUCCESS = 1L;private long timeout = 9999; //获取锁的超时时间/*** 加锁,无阻塞** @param* @param* @return*/public static Boolean tryLock(RedisTemplate redisTemplate, String key, String value, long expireTime) {try {//SET命令返回OK ,则证明获取锁成功Boolean ret = redisTemplate.opsForValue().setIfAbsent(key, value, expireTime, TimeUnit.MILLISECONDS);return ret;} catch (Exception e) {e.printStackTrace();return false;}return false;}/*Long start = System.currentTimeMillis();for(;;){//SET命令返回OK ,则证明获取锁成功Boolean ret = redisTemplate.opsForValue().setIfAbsent(key, value, expireTime, TimeUnit.SECONDS);return ret;//否则循环等待,在timeout时间内仍未获取到锁,则获取失败long end = System.currentTimeMillis() - start;if (end>=timeout) {return false;}}*//*** 解锁** @param* @param* @return*/public static Boolean unlock(RedisTemplate redisTemplate, String key, String value) {try {String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";RedisScript<String> redisScript = new DefaultRedisScript<>(script, String.class);//redis脚本执行//Object result = redisTemplate.execute(redisScript, Collections.singletonList(key), value))Object result = redisTemplate.delete(Collections.singletonList(key));if (SUCCESS.equals(result)) {return true;}} catch (Exception e) {e.printStackTrace();return false;}return false;}}
注意:
redisTemplate.execute 是redis脚本执行,可能报错, 具体参考: https://blog.csdn.net/cevery/article/details/108303919
测试:我这里自己创建两个 线程测试
@Slf4j
@Component
public class Schedule {@Resourceprivate RedisTemplate redisTemplate;@Scheduled(cron = "0 0/1 * * * ? ")public void getDeviceStatus() throws InterruptedException {//启动两个线程,测试哪一个能够悠闲抢到Redis锁Test1Runnable test1 = new Test1Runnable();new Thread(test1).start();Test2Runnable test2 = new Test2Runnable();new Thread(test2).start();}//自定义个唯一的Key值public String key = "ZX123456789";//保存数据方法public boolean testSave(){//获取锁boolean isOK = RedisLock.tryLock(redisTemplate, key, "key+1", 2000);//处理业务 ,然后释放锁if(isOK){System.out.println("处理完业务,释放锁==="+RedisLock.unlock(redisTemplate, key, "key+1"));}return isOK;}class Test1Runnable implements Runnable {@Overridepublic void run() {boolean result = testSave();log.info(Thread.currentThread().getName()+"Test1获取锁:"+result);}}class Test2Runnable implements Runnable {@Overridepublic void run() {boolean result = testSave();log.info(Thread.currentThread().getName()+"Test2获取锁:"+result);}}
}
效果:
JAVA RedisTemplate实现(加锁/解锁) 解决高并发问题相关推荐
- java redis队列_redis队列实现高并发怎么用?Java如何使用redis队列解决高并发?
小伙伴们大家好,不知道你们有没有在Java开发中遇到redis队列高并发,这个问题让你很头疼,今天小编就来讲解一下在Java中遇到redis队列高并发了,到底该怎么办. 高并发的业务场景: 我们做商品 ...
- java 高并发商城库存订单处理,下单减库存,如何解决高并发减库存问题
下单减库存,如何解决高并发减库存问题 1. 减库存 一般下单减库存的流程大概是这样的: 1.查询商品库存.这里直接查的Redis中的库存. 2.Redis中的库存减1.这里用到的Redis命令是:in ...
- Java解决高并发秒杀商品
在看本文章之前,需要了解Spring boot搭建和使用 ,本篇文章核心问题是如何解决高并发问题. 开发环境:redis缓存4.0.1,Rabbitmq消息队列,Erlang(这个跟MQ环境有关,先安 ...
- 转发:php解决高并发
php解决高并发(转发:https://www.cnblogs.com/walblog/articles/8476579.html) 我们通常衡量一个Web系统的吞吐率的指标是QPS(Query Pe ...
- Spring Boot实战解决高并发数据入库: Redis 缓存+MySQL 批量入库
前言 最近在做阅读类的业务,需要记录用户的PV,UV: 项目状况:前期尝试业务阶段: 特点: 快速实现(不需要做太重,满足初期推广运营即可) 快速投入市场去运营 收集用户的原始数据,三要素: 谁 在什 ...
- php 文件锁 重发请求,PHP使用文件锁解决高并发问题示例
本文实例讲述了PHP使用文件锁解决高并发问题.分享给大家供大家参考,具体如下: 新建一个.txt文件,文件中什么都不用写. [一].阻塞(等待)模式:(只要有其他进程已经加锁文件,当前进程会一直等其他 ...
- 使用Redis解决高并发方案 以及 思路讲解
NoSQL Not Only SQL的简称.NoSQL是解决传统的RDBMS在应对某些问题时比较乏力而提出的. 即非关系型数据库,它们不保证关系数据的ACID特性,数据之间一般没有关联,在扩展上就非常 ...
- Redis锁解决高并发问题
Redis锁解决高并发问题 redis真的是一个很好的技术,它可以很好的在一定程度上解决网站一瞬间的并发量,例如商品抢购秒杀等活动. redis之所以能解决高并发的原因是它可以直接访问内存,而以往我们 ...
- 乐观锁 -业务判断 解决高并发问题
在解决高并发问题时,如果是分布式系统显然我们只能够使用数据库端加锁机制来解决这个问题,但是这种同步机制或者数据库物理锁机制会牺牲一部分的性能,所以常常以另外一种方式来解决这个问题 就是乐观锁模式 银行 ...
最新文章
- 历经 7 年双 11 实战,阿里巴巴是如何定义云原生混部调度优先级及服务质量的?
- 餐厅前台php,餐厅前台接听电话技巧
- 用GDI+转BMP为WMF、EXIF、EMF格式
- 关于ASP.NET 将数据导出成Excel 的总结[下]
- MySQL 5.7临时表空间
- CANape中使用vCDMStudio批量标定
- hive sql正则表达式总结
- 非科班学生党的2022秋招之路 -- 一路艰辛
- a4纸尺寸在html中是多大,a4纸尺寸是多少厘米(各种标准纸张大小)
- 详解透明网桥的三个功能
- windows c语言新建dos,dos命令怎么用_DOS下创建文件、文件夹
- 使用Xamarin开发(一)安装配置
- 解决iphone插上mac电脑充电不停的断开和链接问题
- mencoder 报错处理
- 【unity shader】unity游戏特效-仿《黑暗欺骗》模型消融消失效果
- java斗地主代码_基于java实现斗地主代码实例解析
- 云产品相关网络概念学习Regison/AZ/VPC
- vue项目对要显示的富文本数据中的图片处理----去掉或控制图片大小
- 2017北大信科夏令营机试E:怪盗基德的滑翔翼
- 标题栏修改背景色或背景图