使用redistemplate模拟获取分布式锁,但是报以下错,实际redis连接没有问题,测试是ok的
@Test
void testLock(){
//RedisTask myTask = new RedisTask();
Thread thread = new Thread(redisTask);
thread.start();
for (int i=0;i<2;i++){
}
}
package com.practice.redisTest.redisTemplate;
import com.practice.redisTest.redisTemplate.RedisLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
@Component
public class RedisTask implements Runnable{
@Autowired
private RedisLock redisLock;
//private RedisLock redisLock = new RedisLock() ;
private String lockKey = "myLock";
@Override
public void run() {
// 1.获取锁
String lockValue = redisLock.getLock(lockKey, 5000, 5);
if (!StringUtils.hasText(lockValue)) {
System.out.println(Thread.currentThread().getName() + ",获取锁失败!");
return;
}
/* try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
// 2.获取锁成功执行业务逻辑
System.out.println(Thread.currentThread().getName() + ",获取成功,lockValue:" + lockValue);
// // 3.释放lock锁
redisLock.unLock(lockKey, lockValue);
}
}
package com.practice.redisTest.redisTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
@SuppressWarnings(value = {"unchecked", "rawtypes"})
@Component
public class RedisLock {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private RedisTemplateUtils redisTemplateUtils;
/**
* 获取锁
* @param lockKey key值
* @param notLockTimeOut 等待时间
* @param lockTimeOut 锁自动过期时间
* @return
*/
public String getLock(String lockKey, int notLockTimeOut, int lockTimeOut) {
// 定义没有获取锁的超时时间
Long endTimeOut = System.currentTimeMillis() + notLockTimeOut;
while (System.currentTimeMillis() < endTimeOut) {
/*String lockValue = UUID.randomUUID().toString();
System.out.println(lockValue);*/
String lockValue = "ceshi";
//获取成功true
Boolean flag = redisTemplateUtils.setCacheNxObject(lockKey,lockValue);
// 如果在多线程情况下谁能够setnx 成功返回true 谁就获取到锁
System.out.println("======"+flag);
if (flag) {
redisTemplateUtils.expire(lockKey, lockTimeOut, TimeUnit.SECONDS);
return lockValue;
}
// 否则情况下 在超时时间内继续循环
}
return null;
}
/**
* 释放锁
* @param lockKey
* @param lockValue
* @return
*/
public Boolean unLock(String lockKey, String lockValue) {
// 确定是对应的锁 ,才删除
if (lockValue.equals(redisTemplateUtils.getCacheObject(lockKey))) {
return redisTemplateUtils.deleteObject(lockKey);
}
return false;
}
}
/**
* 缓存基本的对象,Integer、String、实体类等
*
* @param key 缓存的键值
* @param value 缓存的值
* @param timeout 时间
* @param timeUnit 时间颗粒度
*/
public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) {
redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
}
/**
* setNX
*
* @param key 缓存的键值
* @param value 缓存的值
*/
public <T> Boolean setCacheNxObject(final String key, final T value) {
return redisTemplate.getConnectionFactory().getConnection()
.setNX(key.getBytes(Charset.defaultCharset()), value.toString().getBytes(Charset.defaultCharset()));
}
Exception in thread "Thread-2" org.springframework.data.redis.RedisSystemException: Redis exception; nested exception is io.lettuce.core.RedisException: Connection is closed
at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:74)
at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:41)
at org.springframework.data.redis.PassThroughExceptionTranslationStrategy.translate(PassThroughExceptionTranslationStrategy.java:44)
at org.springframework.data.redis.FallbackExceptionTranslationStrategy.translate(FallbackExceptionTranslationStrategy.java:42)
at org.springframework.data.redis.connection.lettuce.LettuceConnection.convertLettuceAccessException(LettuceConnection.java:272)
at org.springframework.data.redis.connection.lettuce.LettuceConnection.await(LettuceConnection.java:1063)
at org.springframework.data.redis.connection.lettuce.LettuceConnection.lambda$doInvoke$4(LettuceConnection.java:920)
at org.springframework.data.redis.connection.lettuce.LettuceInvoker$Synchronizer.invoke(LettuceInvoker.java:665)
at org.springframework.data.redis.connection.lettuce.LettuceInvoker.just(LettuceInvoker.java:109)
at org.springframework.data.redis.connection.lettuce.LettuceStringCommands.setNX(LettuceStringCommands.java:153)
at org.springframework.data.redis.connection.DefaultedRedisConnection.setNX(DefaultedRedisConnection.java:327)
at com.practice.redisTest.redisTemplate.RedisTemplateUtils.setCacheNxObject(RedisTemplateUtils.java:55)
at com.practice.redisTest.redisTemplate.RedisLock.getLock(RedisLock.java:36)
at com.practice.redisTest.redisTemplate.RedisTask.run(RedisTask.java:19)
at java.lang.Thread.run(Thread.java:748)
Caused by: io.lettuce.core.RedisException: Connection is closed
at io.lettuce.core.protocol.DefaultEndpoint.validateWrite(DefaultEndpoint.java:284)
at io.lettuce.core.protocol.DefaultEndpoint.write(DefaultEndpoint.java:180)
at io.lettuce.core.protocol.CommandExpiryWriter.write(CommandExpiryWriter.java:116)
at io.lettuce.core.RedisChannelHandler.dispatch(RedisChannelHandler.java:191)
at io.lettuce.core.StatefulRedisConnectionImpl.dispatch(StatefulRedisConnectionImpl.java:163)
at io.lettuce.core.AbstractRedisAsyncCommands.dispatch(AbstractRedisAsyncCommands.java:627)
at io.lettuce.core.AbstractRedisAsyncCommands.setnx(AbstractRedisAsyncCommands.java:1581)
at org.springframework.data.redis.connection.lettuce.LettuceInvoker.lambda$just$3(LettuceInvoker.java:109)
... 9 more
Process finished with exit code 0