JAVARedisTemplate实现(加锁解锁)解决⾼并发问题
基于传统的单机模式下的并发锁,已远远不能满⾜当下⾼并发⼤负载的情况,当下常⽤的并发处理如下
1、使⽤synchronized关键字
2、select    for update  乐观锁
3、使⽤redis实现同步锁
⽅案⼀ 适合单机模式,
⽅案⼆ 虽然满⾜多节点服务实例但 对变更操作的吞吐量有影响
⽅案三 基于redis nosql数据库  在效率与横向扩展⽅⾯都⼤⼤优于前两种⽅案
redis  单线程  在⾃⾝设计上⼀定程度可避免想成不安全  再者其效率⾼于关系型数据库
本次实现锁机制  基于redis 的两个指令 查询  ⽹站
指令⼀:SETNX key value
将key设置值为value,如果key不存在,这种情况下等同命令。 当key存在时,什么也不做。SETNX是”SET if Not eXists”的简写。返回值
, 特定值:
1 如果key被设置了
0 如果key没有被设置
指令⼆:GETSET key value
⾃动将key对应到value并且返回原来key对应的value。如果key存在但是对应的value不是字符串,就返回错误。
返回值
: 返回之前的旧值,如果之前Key不存在将返回nil。
步骤⼀, pom⽂件
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apachemons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.6.0</version>
</dependency>
步骤⼆,RedisCacheAutoConfiguration
package com.wh.fig;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.edis.RedisUtil;
slf4j.Slf4j;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.dition.ConditionalOnBean;
import org.springframework.dition.ConditionalOnMissingBean;
import org.springframework.boot.dis.RedisAutoConfiguration;
import t.annotation.Bean;
import t.annotation.Configuration;
import org.tion.RedisConnectionFactory;
import org.RedisTemplate;
import org.StringRedisTemplate;
import org.dis.serializer.Jackson2JsonRedisSerializer;
redis是nosql数据库吗import org.dis.serializer.RedisSerializer;
import org.dis.serializer.StringRedisSerializer;
/**
* Redis缓存配置
*
* @author
*/
@Slf4j
@Configuration
@AutoConfigureAfter({RedisAutoConfiguration.class})
public class RedisCacheAutoConfiguration {
/**
* 重新配置⼀个RedisTemplate
*
* @param factory
* @return
*/
@Bean
public 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);
jackson2JsonRedisSerializer.setObjectMapper(om);
RedisSerializer<String> stringSerializer = new StringRedisSerializer();
// key采⽤String的序列化⽅式
template.setKeySerializer(stringSerializer);
// hash的key也采⽤String的序列化⽅式
template.setHashKeySerializer(stringSerializer);
// value序列化⽅式采⽤jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化⽅式采⽤jackson
template.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.RedisTemplate;
import org.script.DefaultRedisScript;
import org.script.RedisScript;
import java.util.Collections;
import urrent.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 = ute(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;
}
}
注意:
@Slf4j
@Component
public class Schedule {
@Resource
private 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 = Lock(redisTemplate, key, "key+1", 2000);
//处理业务,然后释放锁
if(isOK){
System.out.println("处理完业务,释放锁==="+RedisLock.unlock(redisTemplate, key, "key+1"));
}
return isOK;
}
class Test1Runnable implements Runnable {
@Override
public void run() {
boolean result = testSave();
log.info(Thread.currentThread().getName()+"Test1获取锁:"+result);
}
}
class Test2Runnable implements Runnable {
@Override
public void run() {
boolean result = testSave();
log.info(Thread.currentThread().getName()+"Test2获取锁:"+result);
}
}
}
效果:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。