• 公号-云原生程序员
    2018-06-07
    ReentrantLock是Lock的实现类,是一个互斥的同步器,在多线程高竞争条件下,ReentrantLock比synchronized有更加优异的性能表现。

    1 用法比较
    Lock使用起来比较灵活,但是必须有释放锁的配合动作
    Lock必须手动获取与释放锁,而synchronized不需要手动释放和开启锁
    Lock只适用于代码块锁,而synchronized可用于修饰方法、代码块等


    2 特性比较
        ReentrantLock的优势体现在:
         具备尝试非阻塞地获取锁的特性:当前线程尝试获取锁,如果这一时刻锁没有被其他线程获取到,则成功获取并持有锁
         能被中断地获取锁的特性:与synchronized不同,获取到锁的线程能够响应中断,当获取到锁的线程被中断时,中断异常将会被抛出,同时锁会被释放
         超时获取锁的特性:在指定的时间范围内获取锁;如果截止时间到了仍然无法获取锁,则返回

    3 注意事项
    在使用ReentrantLock类的时,一定要注意三点:
         在finally中释放锁,目的是保证在获取锁之后,最终能够被释放
         不要将获取锁的过程写在try块内,因为如果在获取锁时发生了异常,异常抛出的同时,也会导致锁无故被释放。
         ReentrantLock提供了一个newCondition的方法,以便用户在同一锁的情况下可以根据不同的情况执行等待或唤醒的动作。
    展开
    
     138
  • 逐梦之音
    2018-06-07
    一直在研究JUC方面的。所有的Lock都是基于AQS来实现了。AQS和Condition各自维护了不同的队列,在使用lock和condition的时候,其实就是两个队列的互相移动。如果我们想自定义一个同步器,可以实现AQS。它提供了获取共享锁和互斥锁的方式,都是基于对state操作而言的。ReentranLock这个是可重入的。其实要弄明白它为啥可重入的呢,咋实现的呢。其实它内部自定义了同步器Sync,这个又实现了AQS,同时又实现了AOS,而后者就提供了一种互斥锁持有的方式。其实就是每次获取锁的时候,看下当前维护的那个线程和当前请求的线程是否一样,一样就可重入了。

    作者回复: 正解

     3
     70
  • BY
    2018-06-07
    要是早看到这篇文章,我上次面试就过了。。

    作者回复: 加油

    
     25
  • Jerry银银
    2019-02-01
    先说说点学习感受:
    并发领域的知识点很多也很散,并且知识点之间交错的。比如:synchronized,这个小小的关键字,能够彻底理解它,需要的知识储备有:基本使用场景、对锁的理解、对线程安全的理解、对同步语义的理解、对JMM的理解等等。有时候,一个知识点暂时做不到透彻理解,可能是正常的,需要再继续学习其它的知识点,等到一定时候,回过头来重新学习,会有一种柳暗花明又一村的感觉。我想,这也可能是老师提到的:并发领域相关知识的准备,需要点耐心。

    再说说这篇专栏:
    这篇专栏,在知识扩展部分,我觉得结构不是太清晰。我读了很多遍之后,还是有这种感觉:文章讲了很多东西,但是我却很难说出文章的主题。
    为此,我自己总结了一下知识扩展部分的主线:
    1. 进入并发领域,首先需要理解什么是线程安全,为什么会存在线程不安全,又为什么需要线程安全。这个知识点可参考《Java并发编程实践》,并且我也认为对于线程安全的讲解,这本书堪称权威;
    2. 老师在讲解线程安全这个点的时候,顺其自然地使用了synchronized和ReentrantLock来保证线程安全(即:Java提供的锁机制)同时,老师也稍微讲解了一下synchronized和ReentrantLock的使用和区别;
    3. 最后,老师举了一个ReentrantLock的典型使用场景:ArrayBlockingQueue。ArrayBlockingQueue使用ReentrantLock来实现加锁机制,保证队列的安全读取,并且使用Condition来实现队列阻塞的条件判断和读写端唤醒,特别提一句:具体的实现代码是相当的优雅!
    展开

    作者回复: 非常感谢反馈

    
     16
  • Kyle
    2018-06-07
    最近刚看完《Java 并发编程实战》,所以今天看这篇文章觉得丝毫不费力气。开始觉得,极客时间上老师讲的内容毕竟篇幅有限,更多的还是需要我们课后去深入钻研。希望老师以后讲完课也能够适当提供些参考书目,谢谢。

    作者回复: 后面会对实现做些源码分析,其实还有各种不同的锁...

    
     11
  • Daydayup
    2018-06-13
    我用过读写分离锁,读锁保证速度,写锁保证安全问题。再入锁还是挺好用的。老师写的很棒,学到不少知识。感谢

    作者回复: 非常感谢

    
     7
  • 木瓜芒果
    2018-06-19
    杨老师,您好,synchronized在低竞争场景下可能优于retrantlock,这里的什么程度算是低竞争场景呢?

    作者回复: 这个精确的标准我还真不知道,我觉得可以这么理解:如果大部分情况,每个线程都不需要真的获取锁,就是低竞争;反之,大部分都要获取锁才能正常工作,就是高竞争

    
     6
  • 灰飞灰猪不会灰飞.烟...
    2018-06-07
    ReentrantLock 加锁的时候通过cas算法,将线程对象放到一个双向链表中,然后每次取出链表中的头节点,看这个节点是否和当前线程相等。是否相等比较的是线程的ID。
    老师我理解的对不对啊?

    作者回复: 嗯,并发库里都是靠自己的synchronizer

    
     6
  • 猪哥灰
    2018-06-29
    为了研究java的并发,我先把考研时候的操作系统教材拿出来再仔细研读一下,可见基础之重要性,而不管是什么语言,万变不离其宗
    
     5
  • Miaozhe
    2018-06-12
    杨老师,问个问题,看网上有说Condition的await和signal方法,等同于Object的wait和notify,看了一下源码,没有直接的关系。
    ReentractLock是基于双向链表的对接和CAS实现的,感觉比Object增加了很多逻辑,怎么会比Synchronized效率高?有疑惑。

    作者回复: 你看到的很对,如果从单个线程做的事来看,也许并没有优势,不管是空间还是时间,但ReentrantLock这种所谓cas,或者叫lock-free,方式的好处,在于高竞争情况的扩展性,而原来那种频繁的上下文切换则会导致吞吐量迅速下降

     1
     5
  • xinfangke
    2018-06-08
    老师 问你个问题 在spring中 如果标注一个方法的事务隔离级别为序列化 而数据库的隔离级别是默认的隔离级别 此时此方法中的更新 插入语句是如何执行的?能保证并发不出错吗

    作者回复: 这个我没用过,哪位读者熟悉?

     1
     5
  • 加载中……
    2019-02-25
    看到留言区,有个同学问:new ReentrantLock()能不能写到里面,我看了回复,不是很认同,不知道到对不对。其实:new lock和lock api的调用得写到try外面,写到里面会有问题,如下:
    lock() api 可能会抛出异常,如果放到try里面,在finally里面unlock会再抛出异常(因为当前状态不对),这个时候 "解锁异常"会隐藏"加锁异常",也就是异常堆栈只有“解锁异常”没有"加锁异常",而这样会误导程序员吧?,模拟代码如下:
    try {
                //如果lock在try里,且lock抛出异常
                throw new RuntimeException("加锁异常");
            } finally {
                //调用unlock如果lock没有获取到锁会抛出异常,这个在堆栈会隐藏“加锁异常”
                throw new RuntimeException("解锁异常");
            }
    展开
    
     4
  • Neil
    2019-01-07
    可以理解为synchronized是悲观锁 另一个是乐观锁

    作者回复: 基本如此,乐观、悲观是两种不同的处理策略

    
     3
  • 李飞
    2018-06-08
    老师,可以问您一个课外题吗。具备怎样的能力才算是java高级开发
     1
     3
  • sunlight001
    2018-06-07
    老师这里说的低并发和高并发的场景,大致什么数量级的算低并发?我们做管理系统中用到锁的情况基本都算低并发吧

    作者回复: 还真不知道有没有具体标准,但从逻辑上,低业务量不一定是“低竞争”,可能因为程序设计原因变成了“高竞争”

    
     3
  • clz1341521
    2018-08-05
    所有的Lock都是基于AQS来实现了。AQS和Condition各自维护了不同的队列,在使用lock和condition的时候,其实就是两个队列的互相移动。如果我们想自定义一个同步器,可以实现AQS。它提供了获取共享锁和互斥锁的方式,都是基于对state操作而言的。ReentranLock这个是可重入的。其实要弄明白它为啥可重入的呢,咋实现的呢。其实它内部自定义了同步器Sync,这个又实现了AQS,同时又实现了AOS,而后者就提供了一种互斥锁持有的方式。其实就是每次获取锁的时候,看下当前维护的那个线程和当前请求的线程是否一样,一样就可重入了。
    杨老师,我一直是这样用rerentlock的,在使用的类中定义一个static的rerentlock,然后哪个方法中需要用到再 try 中 xx.lock,然后finally中xx.unlock。这样用有没有问题?
    
     2
  • godtrue
    2018-12-15
    没有可修改,不用担心状态会改变,有没有多线程无所谓。
    有可修改,只有一个线程,不用担心状态会被修改错。
    有可修,有多线程,就存在修改错乱的情况,就需要加锁。锁,到底是啥东西呢?锁,本质是啥呢?经常说获取锁,到底是获取的啥呢?用完锁,要释放,释放啥?释放的动作是啥呢?

    锁-本质上就是一种同步机制,能够保证多线程环境下,对共享数据的正确修改。
    同步机制,是什么机制呢?怎么保证的呢?到这里是否就需要操作系统相关的知识才能理解了,能理解锁的作用和特点,但对锁本身认识还是模糊的,不太清楚他是怎么起作用的,他的特点是他内部的什么因素的外在表现?
    恩,先继续,然后再回头看看,也许能领悟出的点什么🤔
    展开
    
     1
  • leleba
    2018-11-02
    这里怎么没有精彩的留言了呢?很难吗,反正我觉得难,但必须要学
    
     1
  • 时间总漫不经心
    2018-08-10
    老师,jmm什么时候将工作内存的值写入到主内存中呢?

    作者回复: volatile读写、同步块这种

    
     1
  • Daydayup
    2018-06-13
    我用过读写分离锁,读锁保证速度,写锁保证安全问题。再入锁还是挺好用的。老师写的很棒,学到不少知识。感谢
    
     1
我们在线,来聊聊吧