学习
实践
活动
工具
TVP
写文章

自旋

自旋:竞争的失败的线程,并不会真实的在操作系统层面挂起等待,而是JVM会让线程做 几个空循环(基于预测在不久的将来就能获得),在经过若干次循环后,如果可以获得,那么进入临界区,如果还不能获得, 适用场景:自旋可以减少线程的阻塞,这对于竞争不激烈,且占用时间非常短的代码块 来说,有较大的性能提升,因为自旋的消耗会小于线程阻塞挂起操作的消耗。 如果的竞争激烈,或者持有的线程需要长时间占用执行同步块,就不适合使用自旋 了,因为自旋锁在获取前一直都是占用cpu做无用功,线程自旋的消耗大于线程阻塞挂起操作的消耗,造成cpu的浪费。

31400

自旋

自旋的具体描述,可以看这里: https://blog.csdn.net/zy010101/article/details/83869140 自旋适合于被持有的时间比较短的场合,这样能避免线程调度的时候花费的成本 正如前面文章中所述,自旋一般作为底层的PV原语来实现其它类型的自旋锁在非抢占式调度中非常有用。 (不抢占,只能等待时间片用完,或者是) 自旋锁在用户层面而言,不被经常使用。APUE中这样写到自旋,从他的描述不难看出,不希望在用户层面使用自旋。 需要注意的是,pthread_spin_lock函数在获取之前一直处于自旋状态,直到获取为止;而pthread_spin_trylock函数如果不能获取,那么立即返回EBUSY错误,它不自旋。 试图对没有加锁的自旋进行解锁,结果是未定义的;如果当前线程已经获取了自旋并加锁,继续加锁的结果也是未定义的。这有可能引起永久自旋

18920
  • 广告
    关闭

    热门业务场景教学

    个人网站、项目部署、开发环境、游戏服务器、图床、渲染训练等免费搭建教程,多款云服务器20元起。

  • 您找到你想要的搜索结果了吗?
    是的
    没有找到

    自旋

    在这一篇中我们主要介绍第一种优化也就是自旋自旋 我们知道线程同步是用线程阻塞的方式来实现的。 这种的优化方式就是自旋自旋并不能代替线程的阻塞,它的目的是为了解决线程频繁的执行暂停和恢复也就是线程切换而存在的。如果其它线程占用的时间较短,那么自旋的优化方式效果就会非常明显。 所以为了解决上述问题,自旋一定有某种条件的限制,而不能让自旋一直等待下去。所以在虚拟机中有规定,自旋循环的次数默认是10次。 自旋本质上只有一种,但虚拟机为了更好的优化于是在JDK 1.6中引入了自适应的自旋。自适应自旋的意思就是循环的次数不是上述所说的默认10次了。而是根据上一个线程获取到时它的自旋时间来决定的。 除此之外自适应自旋还会检测,如果发现对于某一个自旋完成后很少成功的获得,那么在以后要获取这个时将尽可能的省略掉自旋的过程,以避免浪费处理器的资源。

    62630

    自旋

    与互斥类似,自旋保证了公共数据在任意时刻最多只能由一条线程获取使用,不同的是在获取失败后自旋会采取自旋的处理方式。 自旋 自旋是指当一个线程尝试获取某个时,如果该已被其他线程占用,就一直循环检测是否被释放,而不是进入线程挂起或睡眠状态。一旦另外一个线程释放该后,此线程便能获得该自旋存在的问题 1、自旋一直占用CPU,在未获得的情况下,一直运行,如果不能在很短的时间内获得,会导致CPU效率降低。 2、试图递归地获得自旋会引起死锁。 递归程序决不能在持有自旋时调用它自己,也决不能在递归调用时试图获得相同的自旋。 由此可见,我们要慎重的使用自旋自旋适合于使用者保持时间比较短并且竞争不激烈的情况。 正是由于自旋使用者一般保持时间非常短,因此选择自旋而不是睡眠是非常必要的,自旋的效率远高于互斥

    17640

    Java面试题自旋

    自旋spinlock 重点:尝试获取的线程不会立即阻塞,而是采用循环的方式去尝试获取,这样的好处是减少线程上下文切换的消耗,不会堵塞。 this.compareAndSwapInt(var1, var2, var5, var5 + var4)); return var5; } 手敲自旋: 代码: package com.juc.lock; import java.util.Date; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference + new Date()); // 交换不成功则一直自旋 while (! Tue May 05 20:03:00 CST 2020 从结果可以看出,在线程1还没有释放时,线程2无法执行操作,仅仅是进入后不断循环直到线程1释放。 这就是自旋的妙处。

    35920

    Windows 驱动开发 - 自旋,队列自旋,链表自旋的使用.

    目录 windows 驱动开发之自旋结构的使用 一丶自旋 1.1 简介 1.2 使用自旋 1.3 错误的用法 二丶 链表中使用自旋 2.1 简介 三丶队列自旋 3.1 简介 windows 驱动开发之自旋结构的使用 其实自旋就是用来限制多线程对同一数据资源的访问而设定的。 而内核中的自旋与Ring3层的临界区类似。 看看如何使用自旋吧。 1.2 使用自旋 初始化自旋自旋是内核中提供的一种高IRQL的,用同步以独占的方式来访问某个资源。 我们定义一个自旋并且传入进去,他就会给我们进行初始化。 那么以后就是用这个值即可。 使用自旋 使用自旋分别使用以下两个函数即可。 所以在使用队列自旋的时候一定注意不要和自旋混用。 比如等待使用 自旋, 释放使用队列自旋

    49410

    cas与自旋(轻量级就是自旋吗)

    CAS基于乐观思想来设计的,其不会引发阻塞,synchronize会导致阻塞。 原子类 java.util.concurrent.atomic包下的原子类都使用了CAS算法。 而java.util.concurrent中的大多数类的实现都直接或间接的使用了这些原子类。 Unsafe类使Java拥有了类似C语言指针操作内存空间的能力,同时也带来了指针的安全问题。 注意:从1、2步可以看CAS机制实现的自旋,如果线程一直无法获取到,则一直自旋,不会阻塞 CAS和syncronized的比较 CAS线程不会阻塞,线程一致自旋 syncronized会阻塞线程 从Java1.5开始JUC包里提供了一个类AtomicStampedReference来解决ABA问题。 (2)循环时间长开销会比较大:自旋重试时间,会给CPU带来非常大的执行开销 (3)只能保证一个共享变量的原子操作,不能保证同时对多个变量的原子性操作 解决办法: 从Java1.5开始JDK提供了AtomicReference

    18810

    Java---偏向、轻量级自旋、重量级

    synchronized会导致争用不到的线程进入阻塞状态,所以说它是java语言中一个重量级的同步操纵,被称为重量级,为了缓解上述性能问题,JVM从1.5开始,引入了轻量与偏向,默认启用了自旋 明确java线程切换的代价,是理解java中各种的优缺点的基础之一。 了解了markword结构,有助于后面了解java的加锁解锁过程; 小结 前面提到了java的4种,他们分别是重量级自旋、轻量级和偏向,  不同的有不同特点,每种只有在其特定的场景下 ,但是具体如何使用这几种呢,就要看后面的具体分析他们的特性; java中的 自旋 自旋原理非常简单,如果持有的线程能在很短时间内释放资源,那么那些等待竞争的线程就不需要做内核态和用户态之间的切换进入阻塞挂起状态 偏向 Java偏向(Biased Locking)是Java6引入的一项多线程优化。

    83430

    Java并发之高级自旋CLH和MCS

    自旋 自旋(spin lock)是一个典型的对临界资源的互斥手段,自旋是基于CAS原语的,所以它是轻量级的同步操作,它的名称来源于它的特性。 myNode,L个有L个tail),CLH的一种变体被应用在了JAVA并发框架中。 CLH在SMP系统结构下该法是非常有效的。 首先看CLH自旋的实现方式: package concurrent.spinlock; import java.util.concurrent.atomic.AtomicReference; /* 线程2 释放 线程3 获得 线程3 释放 MCS的实现方式: package concurrent.spinlock; import java.util.concurrent.atomic.AtomicReference ,AbstractQueuedSynchronizer是Java并发包的基石之一,而CLH的原理和思想则是AbstractQueuedSynchronizer的基石之一,JDK里面的CLH的是增强改进后的

    1.8K30

    Java 并发编程:AQS 的自旋

    与互斥类似,自旋保证了公共数据在任意时刻最多只能由一条线程获取使用,不同的是在获取失败后自旋会采取自旋的处理方式。 自旋 自旋是一种非阻塞,它的核心机制就在自旋两个字,即用自旋操作来替代阻塞操作。 自旋特点 自旋的核心机制就是死等,所有想要获得的线程都在不停尝试去获取,当然这也会引来竞争问题。 与互斥一样,自旋也只允许一个线程获得自旋适用于持有时间叫短的场景,即保护临界区很小的常见,这个很容易理解,如果持有太久,那么将可能导致大量线程都在自旋,浪费大量CPU资源。 如此一来,没获得的线程也不会被挂起或阻塞,而是不断循环检查状态。 AQS的自旋机制 AQS框架中不管是互斥还是共享实现的基础思想都是基于自旋的机制,不过它对自旋做了优化,这个后面会继续讲解。

    74160

    go 自旋

    自旋自旋是指当一个线程在获取的时候,如果已经被其他线程获取,那么该线程将循环等待,然后不断地判断是否能够被成功获取,直到获取到才会退出循环。 通过死循环检测的标志位, 避免了上下文切换的开销, 但是自旋会消耗CPU资源。自旋就主要用在临界区持时间非常短且CPU资源不紧张的情况下,自旋一般用于多核的服务器。 所以一般用于临界区持时间比较长的操作。 自旋实现基础版本go官方提供了atomic算法相关的包, 我们可以使用它直接实现一个自旋package mainimport ("runtime""sync""sync/atomic")type originSpinLock 21.54 ns/opBenchmarkSpinLockBenchmarkSpinLock-12 66324406 18.29 ns/op参考《go ants源码》《自旋

    21940

    Java并发编程:AQS的自旋

    与互斥类似,自旋保证了公共数据在任意时刻最多只能由一条线程获取使用,不同的是在获取失败后自旋会采取自旋的处理方式。 ? 01 自旋 自旋是一种非阻塞,它的核心机制就在自旋两个字,即用自旋操作来替代阻塞操作。 03 自旋特点 自旋的核心机制就是死等,所有想要获得的线程都在不停尝试去获取,当然这也会引来竞争问题。 与互斥一样,自旋也只允许一个线程获得自旋适用于持有时间叫短的场景,即保护临界区很小的常见,这个很容易理解,如果持有太久,那么将可能导致大量线程都在自旋,浪费大量CPU资源。 05 AQS的自旋机制 AQS框架中不管是互斥还是共享实现的基础思想都是基于自旋的机制,不过它对自旋做了优化,这个后面会继续讲解。

    23840

    自旋是什么?

    自旋:竞争的失败的线程,并不会真实的在操作系统层面挂起等待,而是JVM会让线程做几个空循环(基于预测在不久的将来就能获得),在经过若干次循环后,如果可以获得,那么进入临界区,如果还不能获得,才会真实的将线程在操作系统层面进行挂起 适用场景:自旋可以减少线程的阻塞,这对于竞争不激烈,且占用时间非常短的代码块来说,有较大的性能提升,因为自旋的消耗会小于线程阻塞挂起操作的消耗。 如果的竞争激烈,或者持有的线程需要长时间占用执行同步块,就不适合使用自旋了,因为自旋锁在获取前一直都是占用cpu做无用功,线程自旋的消耗大于线程阻塞挂起操作的消耗,造成cpu的浪费。

    11710

    偏向、轻量级、重量级自旋、自适应自旋

    自旋自旋状态下,当一个线程A尝试进入同步代码块,但是当前的已经被线程B占有时,线程A不进入阻塞状态,而是不停的空转,等待线程B释放。 优点:开启自旋后能减少线程的阻塞,在对于的竞争不激烈且占用时间很短的代码块来说,能提升很大的性能,在这种情况下自旋的消耗小于线程阻塞挂起的消耗。 自适应自旋 自适应意味着自旋的时间不再固定了,而是由前一次在同一个锁上的自旋时间及的拥有者的状态来决定: 如果在同一个对象上,自旋等待之前成功获得过的,并且持有的线程正在运行中,那么虚拟机就会认为这次自旋也很有可能再次成功 相反的,如果对于某个自旋很少成功获得过,那么以后要获取这个时将可能减少自旋时间甚至省略自旋过程,以避免浪费处理器资源。 自适应自旋解决的是“竞争时间不确定”的问题。 因此,可以根据上一次自旋的时间与结果调整下一次自旋的时间。 6. 总结 类型 优点 缺点 适用场景 偏向 加锁和解锁不需要额外的消耗,和执行非同步方法比仅存在纳秒级的差距。

    85310

    CAS(cas自旋原理)

    java.util.concurrent包中借助CAS实现了区别于synchronouse同步的一种乐观。 本文先从CAS的应用说起,再深入原理解析。 JNI:Java Native Interface为JAVA本地调用,允许java调用其他语言。 而compareAndSwapInt就是借助C来调用CPU底层指令实现的。 3.2 使用总线保证原子性   第一个机制是通过总线保证原子性。 处理器使用总线就是来解决这个问题的。所谓总线就是使用处理器提供的一个LOCK#信号,当一个处理器在总线上输出此信号时,其他处理器的请求将被阻塞住,那么该处理器可以独占使用共享内存。    自旋CAS如果长时间不成功,会给CPU带来非常大的执行开销。

    14710

    CAS 无优化=自旋=乐观

    实现都是CAS/** * 解决同样的问题的更高效的方法,使用AtomXXX类 * AtomXXX类本身方法都是原子性的,但不能保证多个方法连续调用是原子性的 * @author */import java.util.ArrayList ;import java.util.List;import java.util.concurrent.atomic.AtomicInteger;public class T01_AtomicInteger

    5620

    转:自旋(spinlock)

    自旋与互斥有点类似,只是自旋不会引起调用者睡眠,如果自旋已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋的保持者已经释放了,"自旋"一词就是因此而得名。    由于自旋使用者一般保持时间非常短,因此选择自旋而不是睡眠是非常必要的,自旋的效率远高于互斥。    如果在获取自旋时,没有任何执行单元保持该,那么将立即得到;如果在获取自旋已经有保持者,那么获取操作将自旋在那里,直到该自旋的保持者释放了。    无论是互斥,还是自旋,在任何时刻,最多只能有一个保持者,也就说,在任何时刻最多只能有一个执行单元获得。   自旋的API有: spin_lock_init(x)   该宏用于初始化自旋x。 spin_lock(lock)   该宏用于获得自旋lock,如果能够立即获得,它就马上返回,否则,它将自旋在那里,直到该自旋的保持者释放,这时,它获得并返回。总之,只有它获得才返回。

    35010

    自旋spin_lock

    自旋的引入 原子变量适用在多核之间多单一共享变量进行互斥访问,如果要保护多个变量,并且这些变量之间有逻辑关系时,原子变量就不适用了。例如:常见的双向链表。假设有三个链表节点A、B、C。 如果是0说明可以获得;如果不为0,说明自旋处于上锁状态,不能访问,执行bne 1b指令,跳到标号1处不停执行。 如果为0,表明更新的状态成功;如果不为0表明的状态没哟更新成功,执行”bne 1b”,跳转到标号1继续执行。 %w1, %w0, %w0, ror #16 if(next == owner) 判断next是否等于owner cbz %w1, 3f if(newval == 0) 进入临界区 2: wfe 自旋等待 Owner值存放在tmp中 eor %w1, %w2, %w0, lsr #16 if(next == owner) 判断next是否等于owner cbnz %w1, 2b 如果不等跳到标号2自旋

    43551

    公平非公平可重入自旋

    JAVA中我们知道有很多加锁的方式,比如常见的 通过synchronized关键字,还有Lock,还有之前说原子CAS操作时有看到过的死循环方式的自旋。 借此来说一下的分类: 公平: 是指多个线程按照申请的顺序来获取,每次获取时会先查看此维护的等待队列。先到先得。 自旋(spinlock): 是指尝试获取的线程不会立即进行阻塞,而是采用循环的方式去尝试获取,这样的好处是减少了线程之间的上下文切换消耗,缺点是循环会消耗CPU性能。 那我们就根据他所提供的方法来自己写一个自旋,借此来复习一下之前的原子类操作知识点。 我们可以看到线程B在A释放之后才成功的获取到了。 以上就是通过CAS原子操作实现的一个CAS自旋

    56421

    常见的Java总结:公平,独享,互斥,乐观,分段,偏向自旋等等

    整理了100+个Java项目教程+笔记+源码。 公平 / 非公平 公平 公平是指多个线程按照申请的顺序来获取。 看到一个经典的讲解,使用自旋来模拟一个不可重入,代码如下 import java.util.concurrent.atomic.AtomicReference; public class UnreentrantLock 在Javajava.util.concurrent.atomic包下面的原子变量类就是使用了乐观的一种实现方式CAS实现的。 但是自旋不会引起调用者睡眠,如果自旋已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋的保持者已经释放了,”自旋”一词就是因此而得名。 Java如何实现自旋? 2、上面Java实现的自旋不是公平的,即无法满足等待时间最长的线程优先获取。不公平的就会存在“线程饥饿”问题。

    70250

    扫码关注腾讯云开发者

    领取腾讯云代金券