• 公号-云原生程序员
    2018-06-12
    自旋锁:竞争锁的失败的线程,并不会真实的在操作系统层面挂起等待,而是JVM会让线程做几个空循环(基于预测在不久的将来就能获得),在经过若干次循环后,如果可以获得锁,那么进入临界区,如果还不能获得锁,才会真实的将线程在操作系统层面进行挂起。

    适用场景:自旋锁可以减少线程的阻塞,这对于锁竞争不激烈,且占用锁时间非常短的代码块来说,有较大的性能提升,因为自旋的消耗会小于线程阻塞挂起操作的消耗。
    如果锁的竞争激烈,或者持有锁的线程需要长时间占用锁执行同步块,就不适合使用自旋锁了,因为自旋锁在获取锁前一直都是占用cpu做无用功,线程自旋的消耗大于线程阻塞挂起操作的消耗,造成cpu的浪费。
    展开

    作者回复: 不错,自旋是种乐观情况的优化

    
     83
  • yearning
    2018-06-12
    这次原理真的看了很久,一直鼓劲自己,看不懂就是说明自己有突破。

    下面看了并发编程对于自旋锁的了解,同时更深刻理解同步锁的性能。

    自旋锁采用让当前线程不停循环体内执行实现,当循环条件被其他线程改变时,才能进入临界区。

    由于自旋锁只是将当前线程不停执行循环体,不进行线程状态的改变,所以响应会更快。但当线程不停增加时,性能下降明显。
    线程竞争不激烈,并且保持锁的时间段。适合使用自旋锁。

    为什么会提出自旋锁,因为互斥锁,在线程的睡眠和唤醒都是复杂而昂贵的操作,需要大量的CPU指令。如果互斥仅仅被锁住是一小段时间,
    用来进行线程休眠和唤醒的操作时间比睡眠时间还长,更有可能比不上不断自旋锁上轮询的时间长。

    当然自旋锁被持有的时间更长,其他尝试获取自旋锁的线程会一直轮询自旋锁的状态。这将十分浪费CPU。

    在单核CPU上,自旋锁是无用,因为当自旋锁尝试获取锁不成功会一直尝试,这会一直占用CPU,其他线程不可能运行,
    同时由于其他线程无法运行,所以当前线程无法释放锁。

    混合型互斥锁, 在多核系统上起初表现的像自旋锁一样, 如果一个线程不能获取互斥锁, 它不会马上被切换为休眠状态,在一段时间依然无法获取锁,进行睡眠状态。

    混合型自旋锁,起初表现的和正常自旋锁一样,如果无法获取互斥锁,它也许会放弃该线程的执行,并允许其他线程执行。

    切记,自旋锁只有在多核CPU上有效果,单核毫无效果,只是浪费时间。


    以上基本参考来源于:
    http://ifeve.com/java_lock_see1/
    http://ifeve.com/practice-of-using-spinlock-instead-of-mutex/
    展开

    作者回复: 很不错总结

     1
     43
  • jacy
    2018-06-19
    看了大家对自旋锁的评论,我的收获如下:
    1.基于乐观情况下推荐使用,即锁竞争不强,锁等待时间不长的情况下推荐使用
    2.单cpu无效,因为基于cas的轮询会占用cpu,导致无法做线程切换
    3.轮询不产生上下文切换,如果可估计到睡眠的时间很长,用互斥锁更好

    作者回复: 不错

     3
     20
  • sunlight001
    2018-06-12
    自旋锁是尝试获取锁的线程不会立即阻塞,采用循环的方式去获取锁,好处是减少了上下文切换,缺点是消耗cpu

    作者回复: 不错

    
     17
  • Roysatm
    2019-02-17

    1.synchronized锁,可分为偏向锁、轻量级锁、重量级锁。在jvm没有显示关闭偏向锁的情况下,初始状态时默认是偏向锁时,
    线程请求先通过CAS替换mark word中threadId,如果替换成功则该线程持有当前锁。如果替换失败,锁会升级为轻量级锁,
    线程请求会尝试CAS替换mark word中指向栈中锁记录的指针,如果替换成功则该线程持有当前锁。
    如果替换失败,当前线程会自旋一定次数,继续尝试获取CAS替换,如果超过一定自旋次数,锁升级为重量级锁。

    synchronized锁是调用系统内核互斥锁实现的,线程在获取synchronized锁失败后,也会进入一个等待获取锁队列中(系统内核实现的),
    线程会由运行态切换到阻塞态,让出CPU,待其他线程释放锁后唤醒它。

    synchronize锁重(1.6之后jvm有优化)就是重在两点,一是调用内核互斥锁实现,二是线程获取锁失败会变成阻塞态,让出CPU,等待唤醒(有一定的上下文切换)
    展开
    
     9
  • 陈一嘉
    2018-06-12
    自旋锁 for(;;)结合cas确保线程获取取锁

    作者回复: 差不多

    
     8
  • Miaozhe
    2018-06-12
    杨老师,偏斜锁有什么作用?还是没有看明白,如果只是被一个线程获取,那么锁还有什么意义?
    另外,如果我有两个线程明确定义调用同一个对象的Synchronized块,JVM默认肯定先使用偏斜锁,之后在升级到轻量级所,必须经过撤销Revoke吗?编译的时候不会自动优化?

    作者回复: 我理解偏斜锁就是为了优化那些没有并发却写了同步逻辑的代码;javac编译时能判断的是有限的;一旦有另外线程想获取,就会revoke,而且开销明显

    
     6
  • 灰飞灰猪不会灰飞.烟...
    2018-06-12
    老师 AQS就不涉及用户态和内核态的切换了 对吧?

    作者回复: 我理解是,cas是基于特定指令

    
     5
  • 苦行僧
    2019-02-18
    轻量级锁和重量级锁没有详细说明和区别,仅从名字不好区别
    
     4
  • Jerry银银
    2019-02-02
    『其逻辑是先试着修改,然后通过 validate 方法确认是否...』
    这里面先试着修改写错了,小编帮忙改下吧,应该是:『其逻辑是先试着读,然后....』 我看到留言中,有其它同学早就提出了,但是一直没有被修正。。。。

    作者回复: 谢谢指出

    
     3
  • stephen chow
    2018-10-01
    StampLock是先试着读吧?你写的先试着修改。。

    作者回复: 嗯,是有点写跑偏了,看上下文倒也能理解,谢谢指出

    
     3
  • Miaozhe
    2018-06-13
    杨老师,看到有回复说自旋锁在单核CPU上是无用,感觉这个理论不准确,因为Java多线程在很早时候单核CPC的PC上就能运行,计算机原理中也介绍,控制器会轮巡各个进程或线程。而且多线程是运行在JVM上,跟物理机没有很直接的关系吧?

    作者回复: 已回复,我也认为单核无用

    
     3
  • 刘杰
    2018-07-12
    偏斜锁和轻量级锁的区别不是很清晰
    
     2
  • 随心而至
    2019-09-18
    AtomicInteger中使用的自旋spin, 其实就是不断尝试,直到CAS成功。
    public final int getAndUpdate(IntUnaryOperator updateFunction) {
            int prev, next;
            do {
                prev = get();
                next = updateFunction.applyAsInt(prev);
            } while (!compareAndSet(prev, next));
            return prev;
        }
    展开
    
     1
  • 张天屹
    2019-04-01
    自旋锁我理解了,但是没用过,请问其对于Java来说是jdk提供的api还是JVM层面的实现,还是OS层面的实现呢?
    
     1
  • (💐亮亮💐)
    2018-08-22
    自旋锁失败后,不是进入同步等待队列吗?
    
     1
  • clz1341521
    2018-08-05
    自旋锁是一种乐观优化
    自旋锁:竞争锁的失败的线程,并不会真实的在操作系统层面挂起等待,而是JVM会让线程做几个空循环(基于预测在不久的将来就能获得),在经过若干次循环后,如果可以获得锁,那么进入临界区,如果还不能获得锁,才会真实的将线程在操作系统层面进行挂起。

    适用场景:自旋锁可以减少线程的阻塞,这对于锁竞争不激烈,且占用锁时间非常短的代码块来说,有较大的性能提升,因为自旋的消耗会小于线程阻塞挂起操作的消耗。
    
     1
  • gesanri
    2018-08-04
    我有一个疑问,最后这个stampedlock的例子,access方法中,调用读乐观锁之后直接就进行read操作,但这个时候不知道validate的结果,如果validate为false,还要再read一次,为什么不先判断validate为true再read呢?是因为read这个操作太轻量级了吗?
    
     1
  • 苍天大树
    2018-08-04
    第一次回答问题哈,自旋锁就是当获取锁失败后,自己定时循环去获取锁,不进入休眠状态。这样的好处就是快,坏处就是消耗cpu
    
     1
  • Cui
    2018-06-22
    老师你好 心中一直有个疑问:synchronize和AQS的LockSupport同样起到阻塞线程的作用,这两者的区别是什么?能不能从实现原理和使用效果的角度说说?

    作者回复: LockSupport park是waiting,另一个是blocked;具体底层,马上一篇有说明

    
     1
我们在线,来聊聊吧