使用工具:Apache an
测压命令: ab -n 100 -c 100 http://www.baidu.com -n代表模拟100个请求,-c代表模拟100个并发,相当于100个人同时访问
ab -t 60 -c 100 http://www.baidu.com 60秒100个并发,不断发送请求
并发处理:
1.加synchronized锁单线程处理、缺点: 无法做到细粒度控制 只适合单点的情况 同时运行内存缓慢,效率低(出现等待情况)
2.redis分布式锁:
可以支撑每秒10多万的并发,支持分布式,可以更细粒的控制代码(多台机器上多个线程对一个数据进行操作的互斥)
SETNX key value
将key设置值为value,如果key不存在,这种情况下等同于SET命令,当key存在时,什么也不做
GETSET key value
自动将key对应到value并且返回原来key和对应的value. 如果key存在但是对应的value不是字符串,就返回错误
DEMO演示:
加锁处理方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
@Component @Slf4j public class RedisLock { @Autowired private StringRedisTemplate stringRedisTemplate; //加锁 /* * @param key id * @param value 当前时间+超时时间 * * */ public boolean lock(String key,String value){ if (stringRedisTemplate.opsForValue().setIfAbsent(key,value)){ return true ; //加锁成功就返回true } //不加下面这个可能出现死锁情况 //代码value加了过期时间* @param value 当前时间+超时时间
//获取上一个锁的时间,并判断是否小于当前时间,小于就下一步判断,就返回true加锁成功
String currentValue=stringRedisTemplate.opsForValue().get(key); //如果锁过期 if (!StringUtils.isEmpty(currentValue) && Long.parseLong(currentValue)<System.currentTimeMillis()){ //存储时间要小于当前时间 //出现死锁的另一种情况,当多个线程进来后都没有返回true,接着往下执行,执行代码有先后,而if判断里只有一个线程才能满足条件
//oldValue=currentValue
//多个线程进来后只有其中一个线程能拿到锁(即oldValue=currentValue),其他的返回false
String oldValue=stringRedisTemplate.opsForValue().getAndSet(key,value); if (!StringUtils.isEmpty(oldValue)&& oldValue.equals(currentValue)){ //上一个时间不为空,并且等于当前时间 return true ; } } return false ; //失败返回false } //解锁 public void unlock(String key,String value){ //执行删除可能出现异常需要捕获 try { String currentValue = stringRedisTemplate.opsForValue().get(key); if (!StringUtils.isEmpty(currentValue) && currentValue.equals(value)) { //如果不为空,就删除锁 stringRedisTemplate.opsForValue().getOperations().delete(key); } } catch (Exception e){ log.error( "[redis分布式锁] 解锁" ,e); } } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
//秒杀demo pprivate static final int TIMEOUT= 10 * 1000 ; //超时时间设置为10s @Autowrite private RedisLock redisLock; public void method(String id){ //加锁-死锁出现:即在加锁后运行程序出现意外报了异常,而此时还没调用解锁方法 //那么在下一个线程调用加锁方法是就不能set,直接返回fale,然后一直停留在加锁失败状态 这就出现了死锁
long time=System.currentTimeMillis()+TIMEOUT; //如果加锁不成功就抛出异常 if (!redisLock.lock.get(id,String.valueof(time))){ throw new WechatSellException( 101 , "哎哟喂,人也太多了,换个姿势再试试" ); } //加锁成功就实现业务代码处理 //1.查询该商品库存,为0表示活动结束 //2.下单 3 .扣库存 //解锁 redisLock.unlock(id,String.valueof(time))); } |