我在试验redis击穿问题时,在客户端用Date.getTime()方法进行耗时记录,以下是客户端代码:
@GetMapping("/breakdown")
public void breakdown() throws UnsupportedEncodingException, InterruptedException {
long ti = new Date().getTime();
CyclicBarrier cyclicBarrier = new CyclicBarrier(1000);
CountDownLatch latch = new CountDownLatch(1000);
for (int i = 0; i < 1000; i++) {
new Thread(() -> {
try {
cyclicBarrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
long startTime = new Date().getTime();
final ResponseEntity<Object> forEntity = restTemplate.getForEntity("http://127.0.0.1:8080/index/sku/breakdown/as", Object.class);
final long time = new Date().getTime()- startTime;
System.out.println("耗时:" + time);
long l = 0;
if(time > 500){
l = aj.incrementAndGet();
}
System.out.println("大于500ms的请求数:" + l);
latch.countDown();;
}).start();
}
latch.await();
System.out.println("总耗时:" + (new Date().getTime() - ti));
}
服务端使用jvm的lock锁+双重检查去防击穿,服务端的日志显示db查询只有一次,该次db耗时500+ms,有五分之一的线程在第二次获取到了缓存数据,并进行了锁的竞争,五分之四直接在第一次获取时就得到了缓存数据。但是客户端的打印结果却是:
大于500ms的请求数:994
总耗时:918
从【大于500ms的请求数】这个打印来看,几乎所有线程请求耗时都超过了500ms,但是从【总耗时】耗时来看,有两个问题:1、总耗时不过1000,这没想通,为什么1000个线程运行结束耗时会小于1000ms,难道有的线程执行速度小于了1ms?2、总耗时不过1000ms,怎么又会出现每个线程都超过500ms的耗时呢?我怀疑过getTime方法有阻塞问题,但是调试中对getTime可能进入的同步方法打了断点却没有拦截到一次请求。