Redisson
Redisson 是官方文档推荐的,是基于java写的。
对其初步体验:
maven 依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>2.7.0</version>
</dependency>
代码如下
搭建一个简单的springboot demo进行测试:
- 分布式锁
public class DistributedRedisLock {
// 从配置类中获取redisson对象
private static Redisson redisson = RedissonManager.getRedisson();
private static final String LOCK_TITLE = "redisLock_";
// 加锁
public static boolean acquire(String lockName) {
// 声明key对象
String key = LOCK_TITLE + lockName;
// 获取锁对象
RLock mylock = redisson.getLock(key);
// 加锁,并且设置锁过期时间,防止死锁的产生
mylock.lock(2, TimeUnit.MINUTES);
System.err.println("======lock======" + Thread.currentThread().getName());
// 加锁成功
return true;
}
// 锁的释放
public static void release(String lockName) {
// 必须是和加锁时的同一个key
String key = LOCK_TITLE + lockName;
// 获取所对象
RLock mylock = redisson.getLock(key);
// 释放锁(解锁)
mylock.unlock();
System.err.println("======unlock======" + Thread.currentThread().getName());
}
}
- 使用 JedisPool 连接 redis
我使用的redis没有设置密码,所以将密码注掉了 。
@Configuration
@PropertySource("classpath:application.properties")
public class RedisConfig {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.timeout}")
private int timeout;
@Value("${spring.redis.jedis.pool.max-idle}")
private int maxIdle;
@Value("${spring.redis.jedis.pool.max-wait}")
private long maxWaitMillis;
// @Value("${spring.redis.password}")
// private String password;
@Value("${spring.redis.block-when-exhausted}")
private boolean blockWhenExhausted;
@Bean
public JedisPool jedis() {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(maxIdle);
jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
// 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true
jedisPoolConfig.setBlockWhenExhausted(blockWhenExhausted);
// 是否启用pool的jmx管理功能, 默认true
jedisPoolConfig.setJmxEnabled(true);
JedisPool jedisPool = new JedisPool(jedisPoolConfig, host, port, timeout, null);
return jedisPool;
}
}
- 构建 Controller
@Controller
@RequestMapping(value = "/")
public class HelloController {
private static AtomicInteger count = new AtomicInteger(0);
private static AtomicInteger count1 = new AtomicInteger(0);
@Autowired
RedisUtil redisUtil;
@RequestMapping(value = "hello", method = RequestMethod.GET)
@ResponseBody
public String hello() throws InterruptedException {
String key = "test_num";
int num = count.incrementAndGet();
// 加锁
DistributedRedisLock.acquire(key);
// 处理逻辑
redisUtil.incr("test_num");
// Thread.sleep(1000);
System.out.println("===========第 " + num + " 次请求===================" + redisUtil.get("test_num"));
// 释放锁
DistributedRedisLock.release(key);
return "success";
}
@RequestMapping(value = "hello1", method = RequestMethod.GET)
@ResponseBody
public String hello1() throws InterruptedException {
int num = count1.incrementAndGet();
// 处理逻辑
redisUtil.incr("test_num1");
// Thread.sleep(1000);
System.out.println("TEST1===========第 " + num + " 次请求===================" + redisUtil.get("test_num1"));
return "success";
}
}
- 使用 Junit 模拟并发
<!-- 包依赖 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.9</version>
<scope>test</scope>
<optional>true</optional>
</dependency>
<!-- junit 多线程测试 -->
<!-- https://mvnrepository.com/artifact/net.sourceforge.groboutils/groboutils-core -->
<dependency>
<groupId>net.sourceforge.groboutils</groupId>
<artifactId>groboutils-core</artifactId>
<version>5</version>
<scope>test</scope>
</dependency>
使用 groboutils 模拟多线程,代码如下:
public class Test {
@org.junit.Test
public void test() {
TestRunnable runner = new TestRunnable() {
@Override
public void runTest() throws Throwable {
String url = "http://localhost:8080/hello";
HttpGet get = new HttpGet(url);
CloseableHttpClient client = HttpClientBuilder.create().build();
CloseableHttpResponse response = client.execute(get);
response.close();
}
};
int runnerCount = 10;
// Rnner数组,想当于并发多少个。
TestRunnable[] trs = new TestRunnable[runnerCount];
for (int i = 0; i < runnerCount; i++) {
trs[i] = runner;
}
// 用于执行多线程测试用例的Runner,将前面定义的单个Runner组成的数组传入
MultiThreadedTestRunner mttr = new MultiThreadedTestRunner(trs);
try {
// 开发并发执行数组里定义的内容
mttr.runTestRunnables();
} catch (Throwable e) {
e.printStackTrace();
}
}
}
- 测试结果
先测试一下没有使用 Redis 分布式锁的接口
http://localhost:8080/hello1
TEST1===========第 5 次请求===================9
TEST1===========第 4 次请求===================9
TEST1===========第 7 次请求===================9
TEST1===========第 10 次请求===================9
TEST1===========第 3 次请求===================10
TEST1===========第 1 次请求===================10
TEST1===========第 9 次请求===================10
TEST1===========第 8 次请求===================10
TEST1===========第 6 次请求===================10
TEST1===========第 2 次请求===================10
使用了分布式锁的接口:
http://localhost:8080/hello
======lock======http-nio-8080-exec-1
===========第 1 次请求===================1
======unlock======http-nio-8080-exec-1
======lock======http-nio-8080-exec-6
===========第 3 次请求===================2
======unlock======http-nio-8080-exec-6
======lock======http-nio-8080-exec-8
===========第 7 次请求===================3
======unlock======http-nio-8080-exec-8
======lock======http-nio-8080-exec-2
===========第 2 次请求===================4
======unlock======http-nio-8080-exec-2
======lock======http-nio-8080-exec-9
===========第 6 次请求===================5
======unlock======http-nio-8080-exec-9
======lock======http-nio-8080-exec-4
===========第 9 次请求===================6
======unlock======http-nio-8080-exec-4
======lock======http-nio-8080-exec-3
===========第 4 次请求===================7
======unlock======http-nio-8080-exec-3
======lock======http-nio-8080-exec-7
===========第 5 次请求===================8
======unlock======http-nio-8080-exec-7
======lock======http-nio-8080-exec-5
===========第 8 次请求===================9
======unlock======http-nio-8080-exec-5
======lock======http-nio-8080-exec-10
===========第 10 次请求===================10
======unlock======http-nio-8080-exec-10