肯德基网站是哪家公司做的,电子商务网站建设功能,网站建设更新维护工作总结,南昌做网站要多少钱前言
Redis的INCR命令用于将键的值增加1。如果键不存在#xff0c;则会先将键的值设置为0#xff0c;然后再执行INCR操作。INCR命令的作用是对计数器进行自增操作#xff0c;可以用于实现多种场景#xff0c;比如统计网站访问量、文章访问量、分布式锁等。
一、Redis键之…前言
Redis的INCR命令用于将键的值增加1。如果键不存在则会先将键的值设置为0然后再执行INCR操作。INCR命令的作用是对计数器进行自增操作可以用于实现多种场景比如统计网站访问量、文章访问量、分布式锁等。
一、Redis键之INCR命令
1.INCR 命令介绍
1用法INCR key 2作用将 key 中储存的数字值增一。 3返回值执行 INCR 命令之后 key 的值。 4示例
redis SET PageViewNum 20
OKredis INCR PageViewNum
(integer) 21redis GET PageViewNum # 数字值在 Redis 中以字符串的形式保存
212.INCR 命令在Java中的实战运用
private static final long BEGIN_TIMESTAMP 1701360000; // 开始时间戳1701360000 - 2023-12-01 12:00:00private static final int COUNT_BITS 32;Overridepublic T T redisIncrTest() {HashMapString, Object responseObj new HashMap();responseObj.put(code, 200);responseObj.put(success, true);LocalDateTime now LocalDateTime.now();long currentTimestamp now.toEpochSecond(ZoneOffset.UTC); // 当前时间戳1702882165System.out.println(redisIncrTest :: currentTimestamp - currentTimestamp);long dValue currentTimestamp - BEGIN_TIMESTAMP; // 增长的差值1551885System.out.println(redisIncrTest :: dValue - dValue);String date now.format(DateTimeFormatter.ofPattern(yyyyMMdd)); // 年月日20231218System.out.println(redisIncrTest :: date - date);String REDIS_ICR_KEY REDIS-INCR : date; // REDIS-INCR:20231218long count stringRedisTemplate.opsForValue().increment(REDIS_ICR_KEY); // INCR REDIS-INCR:20231218System.out.println(redisIncrTest :: count - count); // 1String countStr stringRedisTemplate.opsForValue().get(REDIS_ICR_KEY);System.out.println(redisIncrTest :: countStr - countStr); // 1// 说明// 1|或当两个位都为0时结果才为0两边都会计算// 2左移各二进位左移若干位高位丢弃低位补零// 3左移一位相当于乘以2左移32位相当于将某个数乘以2的32次方long rs dValue COUNT_BITS | count;System.out.println(rs);System.out.println(dValue 32);responseObj.put(data, rs);return (T) responseObj;}
二、基于INCR命令实现的分布式锁思路
INCR命令还可以用于实现分布式锁利用Redis的单线程特性将INCR命令作为加锁的操作同时利用Redis的原子性保证加锁的可靠性。
1.实现步骤
1使用stringRedisTemplate.opsForValue().increment(key)方法对指定的key进行自增操作如果key不存在则会自动创建并将其值设置为1。 2判断自增后的返回值是否为1如果为1则说明当前线程获得了锁否则说明锁已经被其他线程占用需要等待。 3在使用完锁后使用stringRedisTemplate.delete(key)方法将锁释放即将key从Redis中删除。
2.示例代码
private static final String REDIS_DISTRIBUTED_LOCK Redis-Distributed-Lock; // 分布式锁名/*** 获取锁*/
private Long acquireLock(String lockName) {Long rs stringRedisTemplate.opsForValue().increment(lockName);System.out.println(acquireLock :: rs - rs);return rs;
}/*** 释放锁*/
private void releaseLock(String lockName) {Boolean flag stringRedisTemplate.delete(lockName);System.out.println(releaseLock :: flag - flag);
}/*** 使用锁*/
private void useLock(String lockName) {Long rs acquireLock(lockName);if (rs 1) {try {System.out.println(嘿嘿拿到锁啦);Thread.sleep(1000);} catch (Exception e) {throw new RuntimeException(e);} finally {releaseLock(lockName);}}
}/*** 测试锁*/
Override
public T T distributedLockTest() {useLock(REDIS_DISTRIBUTED_LOCK);return (T) OK;
}
3.心得
感觉使用INCR命令实现的互斥锁没有SETNX命令实现的优雅以下为基于SETNX命令实现的分布式锁示例。
private static final String REDIS_DISTRIBUTED_LOCK Redis-Distributed-Lock; // 分布式锁名/*** 获取锁*/
private boolean tryLock(String lockKey) {// SETNX Redis-Distributed-Lock 1 # 在指定的key不存在时为key设置指定的值若设置成功则返回1若设置失败则返回0// EXPIRE Redis-Distributed-Lock 10Boolean flag stringRedisTemplate.opsForValue().setIfAbsent(lockKey, 1, 10, TimeUnit.SECONDS);// 注意不能直接返回直接返回存在拆箱操作可能会有空指针return BooleanUtil.isTrue(flag);
}/*** 释放锁*/
private void unLock(String lockKey) {stringRedisTemplate.delete(lockKey);
}/*** 测试锁*/
Override
public T T distributedLockTest() {boolean isLock tryLock(REDIS_DISTRIBUTED_LOCK);if (isLock) {try {System.out.println(嘿嘿拿到锁啦);} catch (Exception e) {throw new RuntimeException(e);} finally {unLock(REDIS_DISTRIBUTED_LOCK);}}return (T) OK;
}
这里有个问题。假如线程一获得锁之后因为某种情况进入了阻塞状态那么当锁过期以后线程二就拿到锁执行到一半线程一开始唤醒执行而此时线程二持有的锁就会被线程一释放掉其它线程也如此反复那咋整
解决办法就是在获取锁时存入线程标志在释放锁时先判断锁中的线程标志判断是否与当前线程标志一致若一致则释放锁否则不释放。
/*** 获取锁*/
private boolean tryLock(String lockKey) {// SETNX Redis-Distributed-Lock 1 # 在指定的key不存在时为key设置指定的值若设置成功则返回1若设置失败则返回0// EXPIRE Redis-Distributed-Lock 10String val LOCK- Thread.currentThread().getName();Boolean flag stringRedisTemplate.opsForValue().setIfAbsent(lockKey, val, 10, TimeUnit.SECONDS);// 注意不能直接返回直接返回存在拆箱操作可能会有空指针return BooleanUtil.isTrue(flag);
}/*** 释放锁*/
private void unLock(String lockKey) {String threadLockName LOCK- Thread.currentThread().getName();String val stringRedisTemplate.opsForValue().get(lockKey);// 只有同一个线程才能主动释放锁if (threadLockName.equals(val)) {stringRedisTemplate.delete(lockKey);}
}