一篇好文,带你深入了解Lock锁 !

1.为什么需要Lock为什么synchronized不够用,还需要LockLock和synchronized这两个最常见的锁都可以达到线程安全的目的,但是功能上有很大不同。Lock并不是用来代替synchronized的而是当使用synchronized不满足情况或者不合适的时候来提供高级功能的2.    为什么synchronized不够用效率低:锁的释放情况较少,试图获得锁不能设定超时,不能中断一个正在试图获得锁的线程不够灵活:加锁和释放的时候单一,每个锁仅有单一的条件可能是不够的无法知道是否成功的获取锁2.Lock锁的意义与使用synchronized方法和语句相比, Lock实现提供了更广泛的锁操作。 它们允许更灵活的结构,可以具有完全不同的属性,并且可以支持多个关联的Condition对象。锁是一种用于控制多个线程对共享资源的访问的工具。 通常,锁提供对共享资源的独占访问,一次只能有一个线程可以获取该锁,并且对共享资源的所有访问都需要首先获取该锁。 但是,某些锁可能允许并发访问共享资源,例如ReadWriteLock的读取锁。使用synchronized方法或语句可访问与每个对象关联的隐式监视器锁,但会强制所有锁的获取和释放以块结构方式进行。当获取多个锁时,它们必须以相反的顺序释放锁。虽然用于synchronized方法和语句的作用域机制使使用监视器锁的编程变得更加容易,并且有助于避免许多常见的涉及锁的编程错误,但在某些情况下,您需要以更灵活的方式使用锁。 例如,某些用于遍历并发访问的数据结构的算法需要使用“移交”或“链锁”:您获取节点A的锁,然后获取节点B的锁,然后释放A并获取C,然后释放B并获得D等。 Lock接口的实现通过允许在不同范围内获取和释放锁,并允许以任意顺序获取和释放多个锁,从而启用了此类技术。3.锁的用法灵活性的提高带来了额外的责任。 缺少块结构锁定需要手动的去释放锁。 在大多数情况下,应使用以下惯用法:Lock lock = new ReentrantLock();lock.lock();try{}finally {  lock.unlock();}当锁定和解锁发生在不同的范围内时,必须小心以确保通过try-finally或try-catch保护持有锁定时执行的所有代码,以确保在必要时释放锁定。Lock实现通过使用非阻塞尝试获取锁( tryLock() ),尝试获取可被中断的锁( lockInterruptibly以及尝试获取锁),提供了比使用synchronized方法和语句更多的功能。可能会超时( tryLock(long, TimeUnit) )。Lock类还可以提供与隐式监视器锁定完全不同的行为和语义,例如保证顺序,不可重用或死锁检测。 如果实现提供了这种特殊的语义,则实现必须记录这些语义。请注意, Lock实例只是普通对象,它们本身可以用作synchronized语句中的目标。 获取Lock实例的监视器锁与调用该实例的任何lock方法没有指定的关系。 建议避免混淆,除非在自己的实现中使用,否则不要以这种方式使用Lock实例。4.内存同步所有Lock实现必须强制执行与内置监视器锁所提供的相同的内存同步语义,如Java语言规范中所述 :一个成功的lock操作具有同样的内存同步效应作为一个成功的锁定动作。一个成功的unlock操作具有相同的存储器同步效应作为一个成功的解锁动作。不成功的锁定和解锁操作以及可重入的锁定/解锁操作不需要任何内存同步效果。实施注意事项锁获取的三种形式(可中断,不可中断和定时)在其性能特征可能有所不同。 此外,在给定的Lock类中,可能无法提供中断正在进行的锁定的功能。 因此,不需要为所有三种形式的锁获取定义完全相同的保证或语义的实现,也不需要支持正在进行的锁获取的中断。 需要一个实现来清楚地记录每个锁定方法提供的语义和保证。 在支持锁获取中断的范围内,它还必须服从此接口中定义的中断语义:全部或仅在方法输入时才这样做。5.Lock提供的接口5.1 获取锁void lock(); // 获取锁。最普通的的获取锁,如果锁被其他线程获取则进行等待lock不会像synchronized一样在异常的时候自动释放锁因此必须在finally中释放锁,以保证发生异常的时候锁一定被释放注意:lock()方法不能被中断,这会带来很大的隐患:一旦陷入死锁、lock()就会陷入永久等待状态5.2 获取中断锁void lockInterruptibly() throws InterruptedException;除非当前线程被中断,否则获取锁。获取锁(如果有)并立即返回。如果该锁不可用,则出于线程调度目的,当前线程将被挂起,并在发生以下两种情况之一之前处于休眠状态:该锁是由当前线程获取的;其他一些线程中断当前线程,并支持锁定获取的中断。如果当前线程:在进入此方法时已设置其中断状态;要么获取锁时被中断,并且支持锁获取的中断,然后抛出InterruptedException并清除当前线程的中断状态。注意事项在某些实现中,中断锁获取的能力可能是不可能的,并且如果可能的话可能是昂贵的操作。 程序员应意识到可能是这种情况。 在这种情况下,实现应记录在案。与正常方法返回相比,实现可能更喜欢对中断做出响应。Lock实现可能能够检测到锁的错误使用,例如可能导致死锁的调用,并且在这种情况下可能引发(未经检查的)异常。注意 synchronized 在获取锁时是不可中断的5.3 尝试获取锁boolean tryLock();非阻塞获取锁(如果有)并立即返回true值。 如果锁不可用,则此方法将立即返回false值。相比于Lock这样的方法显然功能更加强大,我们可以根据是否能获取到锁来决定后续程序的行为注意:该方法会立即返回,即便在拿不到锁的时候也不会在一只在那里等待该方法的典型用法是:Lock lock = new ReentrantLock();if(lock.tryLock()){  try{    // TODO  }finally {    lock.unlock();  }}else{  // TODO}5.4 在一定时间内获取锁boolean tryLock(long time, TimeUnit unit) throws InterruptedException;如果线程在给定的等待时间内获取到锁,并且当前线程尚未中断,则获取该锁。如果锁可用,则此方法立即返回true值。 如果该锁不可用,则出于线程调度目的,当前线程将被挂起,并处于休眠状态,直到发生以下三种情况之一:该锁是由当前线程获取的。其他一些线程会中断当前线程,并支持锁定获取的中断。经过指定的等待时间如果获得了锁,则返回值true 。如果经过了指定的等待时间,则返回值false 。 如果时间小于或等于零,则该方法将根本不等待。注意事项在某些实现中,中断锁获取的能力可能是不可能的,并且如果可能的话可能是昂贵的操作。 程序员应意识到可能是这种情况。 在这种情况下,实现应记录在案。与正常方法返回或报告超时相比,实现可能更喜欢对中断做出响应。Lock实现可能能够检测到锁的错误使用,例如源码交易可能导致死锁的调用,并且在这种情况下可能引发(未经检查的)异常。5.5 解锁void unlock(); //释放锁。注意事项Lock实现通常会限制哪些线程可以释放锁(通常只有锁的持有者才能释放锁),并且如果违反该限制,则可能引发(未经检查的)异常。5.6 获取等待通知组件Condition newCondition(); //返回绑定到此Lock实例的新Condition实例。该组件与当前锁绑定,当前线程只有获得了锁。 才能调用该组件的wait()方法,而调用后,当前线程将释放锁。注意事项Condition实例的确切操作取决于Lock实现。5.7总结Lock对象锁还提供了synchronized所不具备的其他同步特性,如可中断锁的获取(synchronized在等待获取锁时是不可中断的),超时中断锁的获取,等待唤醒机制的多条件变量Condition等,这也使得Lock锁具有更大的灵活性。Lock的加锁和释放锁和synchronized有同样的内存语义,也就是说下一个线程加锁后可以看到前一个线程解锁前发生的所有操作。6.锁的分类根据一下6种情况可以区分多种不同的锁,下面详细介绍6.1要不要锁住同步资源是否锁住锁名称实现方式例子锁柱悲观锁synchronized、locksynchronized、lock不锁住乐观锁CAS算法原子类、并发容器悲观锁又称互斥同步锁,互斥同步锁的劣势:阻塞和唤醒带来的性能劣势永久阻塞:如果持有锁的线程被永久阻塞,比如遇到了无限循环,死锁等活跃性问题优先级反转悲观锁:当一个线程拿到锁了之后其他线程都不能得到这把锁,只有持有锁的线程释放锁之后才能获取锁。乐观锁:自己才进行操作的时候并不会有其他的线程进行干扰,所以并不会锁住对象。在更新的时候,去对比我在修改期间的数据有没有人对他进行改过,如果没有改变则进行修改,如果改变了那就是别人改的那我就不改了放弃了,或者重新来。开销对比:悲观锁的原始开销要高于乐观锁,但是特点是一劳永逸,临界区持锁的时间哪怕越来越长,也不会对互斥锁的开销造成影响悲观锁一开始的开销比乐观锁小,但是如果自旋时间长,或者不停的重试,那么消耗的资源也会越来越多使用场景:悲观锁:适合并发写多的情况,适用于临界区持锁时间比较长的情况,悲观锁可以避免,大量的无用自旋等消耗乐观锁:适合并发读比较多的场景,不加锁能让读取性能大幅度提高6.2能否共享一把锁是否共享锁名称可以共享锁(读锁)不可以排他锁(独占锁)共享锁:获取共享锁之后,可以查看但是无法修改和删除数据,其他线程此时也可以获取到共享锁也可以查看但无法修改和删除数据案例:ReentrantReadWriteLock的读锁(具体实现后续系列文章会讲解)排他锁:获取排他锁的之后,别的线程是无法获取当前锁的,比如写锁。案例:ReentrantReadWriteLock的写锁(具体实现后续系列文章会讲解)6.3是否排队是否排队锁名称排队公平锁不排队非公平锁非公平锁:先尝试插队,插队失败再排队,非公平是指不完全的按照请求的顺序,在一定的情况下可以进行插队存在的意义:提高效率避免唤醒带来的空档期案例:以ReentrantLock为例,创建对象的时候参数为false(具体实现后续系列文章会讲解)针对tryLock()方法,它是不遵守设定的公平的规则的例如:当有线程执行tryLock的时候一旦有线程释放了锁,那么这个正在执行tryLock的线程立马就能获取到锁即使在它之前已经有其他线程在等待队列中公平锁:排队,公平是指的是按照线程请求的顺序来进行分配锁案例:以ReentrantLock为例,创建对象的时候参数为true(具体实现后续系列文章会讲解)注意:非公平也同样不提倡插队行为,这里指的非公平是指在合适的时机插队,而不是盲目的插队优缺点:非公平锁:优势:更快,吞吐量大劣势:有可能产生线程饥饿公平锁:优势: 线程平等,每个线程按照顺序都有执行的机会劣势:更慢,吞吐量更小6.4 是否可以重复获取同一把锁是否可以重入锁名称可以可重入锁不可以不可重入锁案例:以ReentrantLock为例(具体实现后续系列文章会讲解)6.5是否可以被中断是否可以中断锁名称案例可以可中断锁Lock是可中断锁(因为tryLock和lockInterruptibly都能响应中断)不可以不可中断锁Synchronized就是不可中断锁6.6等锁的过程是否自旋锁名称是自旋锁否阻塞锁使用场景:自旋锁一般用于多核的服务器,在并发度不是很高的情况下,比阻塞锁效率高自旋锁适合临界区比较短小的情况,否则如果临界区很大,线程一旦拿到锁,很久以后才会释放那也不合适的,因为会浪费性能在自旋的时候7.锁优化7.1 虚拟机中带的锁优化自旋锁锁消除锁粗化这三种锁优化的方式在前一篇Synchronized文章种所有讲解7.2写代码的时候锁优化缩小同步代码块尽量不锁住方法减少请求锁的次数避免人为制造热点锁中尽量不要再包含锁选择合适的锁类型或者合适的工具类

(0)

相关推荐

  • 深入理解Java里的各种锁(上)

    不知道你有没有被Java里各种锁搞晕过, 轻量级锁 重量级锁 公平锁 非公平锁  lock 锁,synchronized锁 都有什么区别呢? 先看图再一个一个说: 1.悲观锁 VS 乐观锁 悲观锁:对 ...

  • Synchronized和Lock的区别

    引言 在多线程中,为了使线程安全,我们经常会使用synchronized和Lock进行代码同步和加锁,但是具体两者有什么区别,什么场景下适合用什么可能还不大清楚,主要的区别大致如下: 区别 1.syn ...

  • 一篇二类文带给我们的重要启示

    小学生活是我的一本书 文章来自浙江某小学六年级学生 六年的小学时光匆匆流逝,但也不像朱自清说的那样不留痕迹.相反,它在我心里留下了一本书,一本足以回味一生的书. 从这本书里,我读到了浓浓的师生情.当我 ...

  • 一文带你全面解析postman工具的使用(基础篇)

    postman是一款支持http协议的接口调试与测试工具,其主要特点就是功能强大,使用简单且易用性好 .无论是开发人员进行接口调试,还是测试人员做接口测试,postman都是我们的首选工具之一 .那么 ...

  • 错过猪肉周期?一文带你看懂白糖周期(一)国内篇

    #中粮糖业# $中粮糖业(SH600737)$ $牧原股份(SZ002714)$ 本文为深水分析(公众号 ID: deepwater_invest )原创作品 天下大势,分久必合合久必分,万物皆有周期 ...

  • 这篇文章轻松带你认识光通信,好文不容错过

    主编 原荣,书籍<认识光通信>(ISBN:978-7-111-64182-7),本书为普及光通信技术知识而编写. 相关书籍 书名:认识光通信 作者:原荣 ISBN:978-7-111-64 ...

  • 买房要注意什么?——知乎问答一篇科普类文...

    买房要注意什么?--知乎问答 一篇科普类文章,把开发商最怕让你知道的都告诉你了,干货满满,考虑买房的人可以看看了. 长图 长图

  • 科普|只有地球有水?一文带你了解地外水物质

    水,作为地球上最常见的物质之一,几乎是所有生命的不可或缺之物.人类在探索地外宜居地时,也一直都将液态水的存在作为重要评判标准.那么整个太阳系,甚至在更大的宇宙空间内,是不是只有地球才存在水这种物质呢? ...

  • 天青色等烟雨的天青色是什么?一文带你学会正确区别五大名窑(上)

    宋代有五大名窑之说,分别是汝窑.官窑.哥窑.钧窑.定窑. 在这五大名窑中,汝窑.官窑.哥窑这三地烧制的瓷器都是青瓷:钧窑虽然也属于青瓷,但是它并不是以青色为主的瓷器,它烧制出的瓷器颜色还有玫瑰紫.天蓝 ...

  • 天青色等烟雨的天青色是什么?一文带你学会区分五大名窑(下)

    宋代有五大名窑之说,分别是汝窑.官窑.哥窑.钧窑.定窑. 在这五大名窑中,汝窑.官窑.哥窑这三地烧制的瓷器都是青瓷:钧窑虽然也属于青瓷,但是它并不是以青色为主的瓷器,它烧制出的瓷器颜色还有玫瑰紫.天蓝 ...

  • 一文带你了解新冠疫苗的5条技术路线

    关于"一文带你了解新冠疫苗的5条技术路线",医学教育网编辑为大家搜集整理新冠疫苗种类如下,供大家参考学习. 1.灭活疫苗 灭活疫苗是最传统的经典技术路线:即在体外培养新冠病毒,然后 ...