before
最近接到一个需求,是有一个很重的查询,而且还涉及到钱,别人花钱买了次数,结果在高并发情况下,出现了出现了负的八十多次。
出现了很严重的问题。
after
出现这个问题了以后,第一时间考虑的是加锁,先实现次数扣减无误再来考虑性能的问题,目前实现了使用Lock加锁来实现,以后考虑有没有更好的方法!
理论
Lock lock = new ReentrantLock();
通过这条语句,创建一个成员变量,能够锁住代码块
实操
编码
别看这段代码简单,但是确实是简单,通过下面这段代码,就能够实现try中的内容,
每次只能有一个线程进去我测试了一下QPS,没有加锁时QPS为8左右,每分钟的吞吐量为360左右,
加了锁QPS为6左右,每分钟的吞吐量为500左右,虽然下降的有些明显,
但是还能够接受,加锁以后的处理时间在150ms。
lock.lock();
try {
//需要加锁的代码
} finally {
lock.unlock();
}
之后我们考虑的还有一个问题,就是异步执行,不需要去get,get只是去获取返回值,
你不去get,他也会执行。
//如果执行失败,不要减别人的次数
if (status != null) {
threadPool.submit(() -> {
//减次数
reduceCount(userId, join, spendWatch);
});
}
就是这种看起来很简单的代码,却非常有用,能解决实际的问题。
很重的查询,发送了15个sql,但是却能在140秒能返回,首先考虑
的问题,就是15个sql放到线程池去并行执行,然后查询以后加上缓存
就是非常nice。
贴上缓存的代码
运行的流程是
- 先去redis中查询
- 如果没有查到,就去查,然后放到缓存中
- 如果查到了,直接从缓存中取出
@Cacheable(cacheNames = ClothingTradeConstant.CACHE_NAME, key = "'fmhInfo' + #creditId")
小总结
异步,缓存,队排好,这三者是Java快的秘诀!