• 您真的了解Java中的锁吗?这7种不同维度下的锁知道吗?


    写在开头

    在上几篇博文中,我们聊到过volatile关键字,用它修饰变量可以保证可见性与有序性,但它并不是锁,在使用时并不会阻塞线程,且不保证原子性,属于一种轻量级、高效的同步方式,因此,如果我们的使用场景仅需要保持可见性或者有序性,那可选择volatile,但如果必须保证原子性的话,volatile就不行了。

    在Java多线程中,想真正的保证线程的安全,离不开一个东西,那就是 !我们今天就一起来学习一下Java中的锁,以及常见锁的分类。

    认识锁

    很多面试官在问到Java锁的时候,往往都会这样开头

    同学,你真的了解Java中的锁吗?

    在Java中锁是一种非常重要的同步机制,经过前面的学习我们了解到,在并发编程中,经常会遇到多个线程访问同一个共享资源,当多个线程同时对共享资源操作写时,会导致数据不一致。通过锁的同步机制,可以确保在某一时刻只有一个线程能够访问特定的代码块或对象。

    Java中实现锁的历程

    早在jdk1.5之前就已经引入了synchronized 关键字,这个单词翻译成中文即为“同步”之意, Java 早期版本中,synchronized 属于 重量级锁,效率低下;不过,在 Java 6 之后, synchronized 引入了大量的优化如自旋锁、适应性自旋锁、锁消除、锁粗化、偏向锁、轻量级锁等技术来减少锁操作的开销,这些优化让 synchronized 锁的效率提升了很多。JDK 1.5 开始,引入了并发工具包 java.util.concurrent.locks.Lock,让锁的功能更加丰富。

    常用的锁

    1. synchronized 关键字锁定代码库
    2. 可重入锁 java.util.concurrent.lock.ReentrantLock
    3. 重复读写锁 java.util.concurrent.lock.ReentrantReadWriteLock

    主流锁的分类

    现在锁的分类根据不同维度大致分有7类,话不多说,先上一个思维导图便于记忆!
    image

    悲观锁 / 乐观锁

    悲观锁:一律会对代码块进行加锁,如 synchronized、java.util.concurrent.locks.ReentrantLock;
    乐观锁:默认不会进行并发修改,通常采用 CAS 算法不断尝试更新;
    适应场景:悲观锁适合写操作较多的场景,乐观锁适合读操作较多的场景

    自旋锁

    自旋锁是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,这样的好处是减少线程上下文切换的消耗,缺点是循环占有、浪费 CPU 资源。

    偏向锁 / 轻量级锁 / 重量级锁

    JDK 1.5 之后新增锁的升级机制,提升性能。通过 synchronized 加锁后,一段同步代码一直被同一个线程所访问,那么该线程获取的就是偏向锁;偏向锁被一个其他线程访问时,Java 对象的偏向锁就会升级为轻量级锁;再有其他线程会以自旋的形式尝试获取锁,不会阻塞,自旋一定次数仍然未获取到锁,就会膨胀为重量级锁

    公平锁 / 非公平锁

    公平锁:多个线程按照申请顺序来获取锁。如java.util.concurrent.lock.ReentrantLock.FairSync;
    非公平锁:指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程先获得锁。如 synchronized、java.util.concurrent.lock.ReentrantLock.NonfairSync。

    可重入锁

    指在同一个线程在外层方法获取锁的时候,进入内层方法会自动获取锁。JDK 中基本都是可重入锁,避免死锁的发生。

    独享锁 / 共享锁

    独享锁指锁一次只能被一个线程所持有。synchronized、java.util.concurrent.locks.ReentrantLock 都是独享锁;
    共享锁:指锁可被多个线程所持有。ReadWriteLock 返回的 ReadLock 就是共享锁。

    除了以上这6种锁之外,还有的面试题中提到了粗粒度锁与细粒度锁

    粗粒度锁 / 细粒度锁

    粗粒度锁:就是把执行的代码块都锁定;
    细粒度锁:就是锁住尽可能小的代码块,java.util.concurrent.ConcurrentHashMap 中的分段锁就是一种细粒度锁;
    粗粒度锁和细粒度锁是相对的,没有什么标准。

    总结

    OK,今天关于锁的介绍就写到这里啦,本文先做一个总体上的概括,在后续的更新中会做详细介绍呀!😊

    结尾彩蛋

    如果本篇博客对您有一定的帮助,大家记得留言+点赞+收藏呀。原创不易,转载请联系Build哥!

    image

    如果您想与Build哥的关系更近一步,还可以关注“JavaBuild888”,在这里除了看到《Java成长计划》系列博文,还有提升工作效率的小笔记、读书心得、大厂面经、人生感悟等等,欢迎您的加入!

    image

  • 相关阅读:
    个人投资建设新能源汽车充电桩充电站怎么样?多久能实现回本盈利?
    06在IDEA中创建Java和Web工程,了解不同工程下的类路径,在IDEA中执行Maven命令
    centos 根目录逻辑卷扩容/home -> /
    qtday3
    2022年7月31日--使用C#迈出第一步--使用C#中的数组和foreach语句来存储和循环访问数据序列
    数据结构与算法之美笔记03
    数据工程中的单元测试完全指南
    多人协作代码管理工具 gitlab 实战演练
    ASSERT LOG-POINT 应用
    设计模式 外观模式解决疫情卖菜问题
  • 原文地址:https://www.cnblogs.com/JavaBuild/p/18086232