什么是自旋锁 自旋锁是指当一个线程尝试获取某个锁时,如果该锁已被其他线程占用,就一直循环检测锁是否被释放,而不是进入线程挂起或睡眠状态。

简介: 什么是自旋锁自旋锁是指当一个线程尝试获取某个锁时,如果该锁已被其他线程占用,就一直循环检测锁是否被释放,而不是进入线程挂起或睡眠状态。

什么是自旋锁

自旋锁是指当一个线程尝试获取某个锁时,如果该锁已被其他线程占用,就一直循环检测锁是否被释放,而不是进入线程挂起或睡眠状态。

/**

* 为什么用自旋锁:多个线程对同一个变量一直使用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;
}
}




相关文章
|
8月前
|
设计模式 消息中间件 安全
【JUC】(3)常见的设计模式概念分析与多把锁使用场景!!理解线程状态转换条件!带你深入JUC!!文章全程笔记干货!!
JUC专栏第三篇,带你继续深入JUC! 本篇文章涵盖内容:保护性暂停、生产者与消费者、Park&unPark、线程转换条件、多把锁情况分析、可重入锁、顺序控制 笔记共享!!文章全程干货!
439 1
|
并行计算 安全 Java
Python GIL(全局解释器锁)机制对多线程性能影响的深度分析
在Python开发中,GIL(全局解释器锁)一直备受关注。本文基于CPython解释器,探讨GIL的技术本质及其对程序性能的影响。GIL确保同一时刻只有一个线程执行代码,以保护内存管理的安全性,但也限制了多线程并行计算的效率。文章分析了GIL的必要性、局限性,并介绍了多进程、异步编程等替代方案。尽管Python 3.13计划移除GIL,但该特性至少要到2028年才会默认禁用,因此理解GIL仍至关重要。
1292 16
Python GIL(全局解释器锁)机制对多线程性能影响的深度分析
|
供应链 安全 NoSQL
PHP 互斥锁:如何确保代码的线程安全?
在多线程和高并发环境中,确保代码段互斥执行至关重要。本文介绍了 PHP 互斥锁库 `wise-locksmith`,它提供多种锁机制(如文件锁、分布式锁等),有效解决线程安全问题,特别适用于电商平台库存管理等场景。通过 Composer 安装后,开发者可以利用该库确保在高并发下数据的一致性和安全性。
296 6
|
Java 关系型数据库 MySQL
【JavaEE“多线程进阶”】——各种“锁”大总结
乐/悲观锁,轻/重量级锁,自旋锁,挂起等待锁,普通互斥锁,读写锁,公不公平锁,可不可重入锁,synchronized加锁三阶段过程,锁消除,锁粗化
|
运维 API 计算机视觉
深度解密协程锁、信号量以及线程锁的实现原理
深度解密协程锁、信号量以及线程锁的实现原理
330 2
|
Java 应用服务中间件 测试技术
Java21虚拟线程:我的锁去哪儿了?
【10月更文挑战第8天】
532 0
|
安全 调度 数据安全/隐私保护
iOS线程锁
iOS线程锁
279 0
|
Java API
【多线程】乐观/悲观锁、重量级/轻量级锁、挂起等待/自旋锁、公平/非公锁、可重入/不可重入锁、读写锁
【多线程】乐观/悲观锁、重量级/轻量级锁、挂起等待/自旋锁、公平/非公锁、可重入/不可重入锁、读写锁
192 0
|
安全 Java 程序员
【多线程-从零开始-肆】线程安全、加锁和死锁
【多线程-从零开始-肆】线程安全、加锁和死锁
325 0
|
安全 Linux
Linux线程(十一)线程互斥锁-条件变量详解
Linux线程(十一)线程互斥锁-条件变量详解

热门文章

最新文章