当前位置:网站首页>什么是自旋锁 自旋锁是指当一个线程尝试获取某个锁时,如果该锁已被其他线程占用,就一直循环检测锁是否被释放,而不是进入线程挂起或睡眠状态。 /** * 为什么用自旋锁:多个线程对同一个变量
什么是自旋锁 自旋锁是指当一个线程尝试获取某个锁时,如果该锁已被其他线程占用,就一直循环检测锁是否被释放,而不是进入线程挂起或睡眠状态。 /** * 为什么用自旋锁:多个线程对同一个变量
2022-07-28 13:02:00 【学习微站】
什么是自旋锁
自旋锁是指当一个线程尝试获取某个锁时,如果该锁已被其他线程占用,就一直循环检测锁是否被释放,而不是进入线程挂起或睡眠状态。
/**
* 为什么用自旋锁:多个线程对同一个变量一直使用CAS操作,那么会有大量修改操作,
* 从而产生大量缓存一致性流量,因为每一次CAS操作都会发出广播通知其他处理器,从而影响程序的性能。
*
* 自旋不是阻塞,阻塞被唤醒的代价高,性能较差。自旋是执行空代码,虽然效率高,但是会一直占用CPU,
* 最好是很短时间内获得。
*
* 自旋锁:从等待到解锁,线程一直处于running状态,没有上下文切换。
* 注意死递归、死循环导致死锁。
*/
自旋锁+redis
1、导入redis锁
com.baomidou
lock4j-redisson-spring-boot-starter
2.2.2
2、业务实现
自旋锁+redis
1、导入redis锁
com.baomidou
lock4j-redisson-spring-boot-starter
2.2.2
2、业务实现
@Slf4j
@RunWith(SpringRunner.class)
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest(classes = TaskApplication.class)
public class ExceptionTest {
@Resource
private LockTemplate lockTemplate;
private final String key = "work_redis_default_lock_test";
@Test
public void test() {
LockInfo lockInfo = null;
try {
//请求超时时间小于等于0L,框架会用默认的请求超时时间,第四个参数决定lock方法用框架里面的自旋锁。设置超时时间。请求时间和过期时间是不一样的概念。
lockInfo = lockTemplate.lock(key, 50000,
0L, RedissonLockExecutor.class);
if (null == lockInfo) {
log.warn("未抢到锁,结束, key:{}", key);
return;
}
//模拟业务
long startTime = System.currentTimeMillis();
Thread.sleep(5000);
long endTime = System.currentTimeMillis();
log.info("startTime:{}, endTime:{}, user time:{}", startTime, endTime, endTime - startTime);
} catch (Exception e) {
log.error("e:", e);
} finally {
//释放锁
lockTemplate.releaseLock(lockInfo);
}
}
}
3、结果
2022-07-26 16:47:28.920 INFO 23188 — [ main] ExceptionTest : startTime:1658825243919, endTime:1658825248920, user time:5001
4、dubug
在dubug到这里的时候,实际上,redis已经加了锁。
key是我们定义的key,里面的key类型是hash,key随机产生,value 1。
上锁,其他人无法进来,在外面等待。
设置超时、过期时间,如果中途中断了,这个key也会过期,这样不会影响到其他线程访问,是防止死锁的重要手段。
最后执行释放锁,那redis key会被销毁。
5、源码研究
public LockInfo lock(String key, long expire, long acquireTimeout, Class<? extends LockExecutor> executor) {
acquireTimeout = acquireTimeout < 0L ? this.properties.getAcquireTimeout() : acquireTimeout;
long retryInterval = this.properties.getRetryInterval();
LockExecutor lockExecutor = this.obtainExecutor(executor);
log.debug(String.format(“use lock class: %s”, lockExecutor.getClass()));
expire = !lockExecutor.renewal() && expire <= 0L ? this.properties.getExpire() : expire;
int acquireCount = 0;
String value = LockUtil.simpleUUID();
long start = System.currentTimeMillis();
try {
do {
++acquireCount;
Object lockInstance = lockExecutor.acquire(key, value, expire, acquireTimeout);
if (null != lockInstance) {
return new LockInfo(key, value, expire, acquireTimeout, acquireCount, lockInstance, lockExecutor);
}
TimeUnit.MILLISECONDS.sleep(retryInterval);
} while(System.currentTimeMillis() - start < acquireTimeout);
return null;
} catch (InterruptedException var15) {
log.error("lock error", var15);
throw new LockException();
}
}
实际上这里在执行自旋锁,如果该锁已被其他线程占用,就一直循环检测锁是否被释放,而不是进入线程挂起或睡眠状态。
do {
++acquireCount;
Object lockInstance = lockExecutor.acquire(key, value, expire, acquireTimeout);
if (null != lockInstance) {
return new LockInfo(key, value, expire, acquireTimeout, acquireCount, lockInstance, lockExecutor);
}
TimeUnit.MILLISECONDS.sleep(retryInterval);
} while(System.currentTimeMillis() - start < acquireTimeout);
自旋锁里面getlock trylock获取锁
public RLock acquire(String lockKey, String lockValue, long expire, long acquireTimeout) {
try {
RLock lockInstance = this.redissonClient.getLock(lockKey);
boolean locked = lockInstance.tryLock(acquireTimeout, expire, TimeUnit.MILLISECONDS);
return (RLock)this.obtainLockInstance(locked, lockInstance);
} catch (InterruptedException var9) {
return null;
}
}



边栏推荐
- Holes in [apue] files
- Leetcode depth first and breadth first traversal
- Lyscript get previous and next instructions
- regular expression
- R语言可视化散点图、使用ggrepel包的geom_text_repel函数避免数据点之间的标签互相重叠(使用参数xlim和ylim将标签添加到可视化图像的特定区域、指定标签线段并添加箭头)
- Poj3259 wormhole solution
- R language Visual scatter diagram, geom using ggrep package_ text_ The repl function avoids overlapping labels between data points (add labels to specific areas of the visual image using the parameter
- 30天刷题计划(二)
- R语言使用dpois函数生成泊松分布密度数据、使用plot函数可视化泊松分布密度数据(Poisson distribution)
- 在centos中安装mysql5.7.36
猜你喜欢

安全保障基于软件全生命周期-PSP应用

Multithreading and high concurrency (III) -- source code analysis AQS principle

Implementation of StrCmp, strstr, memcpy, memmove

Security assurance is based on software life cycle -psp application

Operator3 - design an operator

7.依赖注入

Continuous (integration -- & gt; delivery -- & gt; deployment)

How to check if the interface cannot be adjusted? I didn't expect that the old bird of the 10-year test was planted on this interview question

修订版 | 目标检测:速度和准确性比较(Faster R-CNN,R-FCN,SSD,FPN,RetinaNet和YOLOv3)...

30 day question brushing plan (III)
随机推荐
R language ggplot2 visualization: use the ggviolin function of ggpubr package to visualize violin diagrams, set the palette parameter, and customize the border colors of violin diagrams at different l
UVA1599理想路径题解
POJ3259虫洞题解
Lyscript get previous and next instructions
记一次COOKIE的伪造登录
R语言使用lm函数构建多元回归模型(Multiple Linear Regression)、并根据模型系数写出回归方程、使用confint函数给出回归系数的95%置信区间
30天刷题计划(三)
Qt5 development from introduction to mastery -- the first overview
最强分布式锁工具:Redisson
Algorithm --- different paths (kotlin)
R语言使用dpois函数生成泊松分布密度数据、使用plot函数可视化泊松分布密度数据(Poisson distribution)
安全保障基于软件全生命周期-PSP应用
产品经理:岗位职责表
SQL daily practice (Niuke new question bank) - day 4: advanced operators
[basic course of flight control development 7] crazy shell · open source formation UAV SPI (barometer data acquisition)
Tutorial on the principle and application of database system (061) -- MySQL exercise: operation questions 21-31 (V)
使用 IPtables 进行 DDoS 保护
leetcode(442)数组中重复的数据
R language ggplot2 visualization: visualize the scatter diagram and add text labels to the data points in the scatter diagram, using geom of ggrep package_ text_ The rep function avoids overlapping da
《机器学习》(周志华) 第6章 支持向量 学习心得 笔记