1、使用redis实现简单的计数
@Setter
@Getter
public class RedisUtil implements InitializingBean {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Override
public void afterPropertiesSet(){ }
public void set(String key, String val) {
stringRedisTemplate.opsForValue().set(key, val);
}
public void setExpire(String key, String val, long timeout, TimeUnit unit) {
stringRedisTemplate.opsForValue().set(key, val);
stringRedisTemplate.expire(key, timeout, unit);
}
public void set(String key, Object val) {
String value = JSON.toJSONString(val);
stringRedisTemplate.opsForValue().set(key, value);
}
public void setExpire(String key, Object val, long timeout, TimeUnit unit) {
String value = JSON.toJSONString(val);
stringRedisTemplate.opsForValue().set(key, value);
stringRedisTemplate.expire(key, timeout, unit);
}
public String get(String key) {
String val = stringRedisTemplate.opsForValue().get(key);
return val;
}
public boolean hasKey(String key) {
return stringRedisTemplate.hasKey(key);
}
public void delete(String key) {
stringRedisTemplate.delete(key);
}
public long increment(String key) {
long val;
try{
val = stringRedisTemplate.opsForValue().increment(key, 1L);
if(val >= Long.MAX_VALUE) {
stringRedisTemplate.opsForValue().set(key, "1");
val = 0L;
}
} catch(Exception e) {
stringRedisTemplate.opsForValue().set(key, "1");
val = 0L;
}
return val;
}
public long incrementExpire(String key, long timeout, TimeUnit unit) {
long val;
try{
val = stringRedisTemplate.opsForValue().increment(key, 1L);
if(val >= Long.MAX_VALUE) {
stringRedisTemplate.opsForValue().set(key,"1");
val = 1L;
}
} catch(Exception e) {
stringRedisTemplate.opsForValue().set(key, "1");
val = 1L;
}
if(val==1L) {
stringRedisTemplate.expire(key, timeout, unit);
}
return val;
}
public void convertAndSend(String channelTopic, String message){
stringRedisTemplate.convertAndSend(channelTopic,message);
}
/**
* redis 获取自增值
*
* @param key key
* @param incrBy 增量值
* @param timeout 超时时间(seconds)
* @return 返回结果
*/
public long increment(final String key, final long incrBy, final long timeout,final TimeUnit timeUnit) {
long count = stringRedisTemplate.opsForValue().increment(key, incrBy);
if(count == incrBy && timeout > 0) {
stringRedisTemplate.expire(key, timeout, timeUnit);
}
return count;
}
/**
* redis 获取自增值
*
* @param key key
* @param incrBy 增量值
* @return 返回结果
*/
public long decrement(final String key, final long incrBy) {
return stringRedisTemplate.opsForValue().increment(key, incrBy);
}
}
2、使用CountDownLatch对redis计数功能进行并发测试
CountDownLatch其实可以把它看作一个计数器,只不过这个计数器的操作是原子操作,同时只能有一个线程去操作这个计数器,也就是同时只能有一个线程去减这个计数器里面的值。
并发测试使用CountDownLatch的两个使用场景
(1)最大程度上实现并行
(2)让当前线程等待所有线程执行结束开始执行
CountDownLatch还有一个应用场景:死锁检测
CountDownLatch使用缺点:不能够重复使用,只能在初始化的时候进行赋值。
public class SimulationTest extends BaseCacheTest {
@Autowired
private RedisUtil redisUtil;
@Test
public void simulationParallel(){
SimulationTest simulationTest = new SimulationTest();
simulationTest.startTaskAllInOnce(100,new Task());
System.out.println(redisUtil.get("smart"));
}
public long startTaskAllInOnce(int threadNums,final Runnable task){
//闭锁
final CountDownLatch begin = new CountDownLatch(1);
final CountDownLatch end = new CountDownLatch(threadNums);
for(int i = 0; i < threadNums; i++){
Thread thread = new Thread(){
@Override
public void run() {
try {
begin.await();
try{
task.run();
}catch (Exception e){
e.printStackTrace();
}finally {
end.countDown();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();
}
long startTime = System.nanoTime();
System.out.println("All thread is ready.............");
begin.countDown();
try {
end.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("All thread is completed..........");
return System.nanoTime()-startTime;
}
class Task implements Runnable{
@Override
public void run() {
redisUtil.increment("smart",1,1, TimeUnit.MINUTES);
}
}
}
如果不对的地方,请各位大佬指正
参考博客:
(1)https://zapldy.iteye.com/blog/746458